减速方法对蓄电池/电流进行滤波有什么区别

时间:2020-01-24 04:19:39

标签: javascript arrays function functional-programming reduce

Array.prototype.reduceArray.prototype.filter链接时,对当前值(而不是累加器值)进行过滤有什么区别(从概念上讲,在幕后)?

// function union creates a union of all values that appear among arrays
// example A

const union = (...arrays) => {
    return arrays.reduce((acc, curr) => {
      const newElements = acc.filter(el => !curr.includes(el));

      return curr.concat(newElements);
    });
  };
 console.log(union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]));

// output (7) [1, 10, 15, 5, 88, 7, 20]

// example B

const union = (...arrays) => {
    return arrays.reduce((acc, curr) => {
      const newElements = curr.filter(el => !acc.includes(el));

      return acc.concat(newElements);
    });
  }; 
  console.log(union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]));

//output (7) [1, 10, 15, 20, 5, 88, 7]

输出的差异将表明对数组进行评估的顺序为“相反”。据我所知,使用arr.filter时从头到尾对值进行评估,而curr.filter则相反。除此之外,还有其他后果取决于您是否通过累加器或当前值进行过滤?这会在其他情况下引发错误吗?

2 个答案:

答案 0 :(得分:1)

问题不在于在filter中使用reduce,而是问题在于您使用acccurr的顺序

当我遇到这种看起来很奇怪的不一致时,我通常要做的第一步是创建一个测试用例并手动运行它。在这里,您已经为我们创建了一个测试用例...

const testData = [
  [1, 10, 15, 20],
  [5, 88, 1, 7],
  [1, 10, 15, 5],
]

现在,我们需要遍历该函数的每个版本,并查看每个阶段的输出。

要注意的一件事(直到今天晚上才知道!),如果reduce没有收到initialValue作为第二个参数,它将使用数组为initialValue。这意味着我们只需要考虑每个函数的2个执行,而不是3个。?

示例A

const union = (...arrays) => {
  return arrays.reduce((acc, curr) => {
    const newElements = acc.filter(el => !curr.includes(el))

    return curr.concat(newElements)
  })
}

在该函数的第一个版本中,正在发生的事情的简短描述是我们遍历累加器(acc)并删除了当前正在比较的数组中已经存在的所有项目( curr)。然后,我们将该列表添加到curr end 中。

我们将newElements推到curr末尾这一事实很重要。这就是为什么两种不同版本的顺序不同的原因。

首次执行

const acc = [1, 10, 15, 20]
const curr = [5, 88, 1, 7]
const newElements = [10, 15, 20] // these elements exist in acc but not in curr
curr.concat(newElements) === [5, 88, 1, 7, 10, 15, 20]

第二次执行

const acc = [5, 88, 1, 7, 10, 15, 20] // carried over from first execution
const curr = [1, 10, 15, 5]
const newElements = [88, 7, 20] // these elements exist in acc but not in curr
curr.concat(newElements) === [1, 10, 15, 5, 88, 7, 20]

示例B

const union = (...arrays) => {
  return arrays.reduce((acc, curr) => {
    const newElements = curr.filter(el => !acc.includes(el))

    return acc.concat(newElements)
  })
}

在函数的第一个版本中,正在发生的事情的简短描述是,我们遍历了当前正在比较的数组(curr)并删除了累加器中已经存在的所有项目( acc)。然后,将该列表添加到acc的末尾。

在下面的第一次执行结束时,您已经可以看到结果的显示顺序大为不同。

首次执行

const acc = [1, 10, 15, 20]
const curr = [5, 88, 1, 7]
const newElements = [5, 88, 7] // these elements exist in curr but not in acc
acc.concat(newElements) === [1, 10, 15, 20, 5, 88, 7]

第二次执行

const acc = [1, 10, 15, 20, 5, 88, 7] // carried over from first execution
const curr = [1, 10, 15, 5]
const newElements = [] // these elements exist in acc but not in curr
acc.concat(newElements) === [1, 10, 15, 20, 5, 88, 7]

结论

您问题的简短答案是,在累加器和当前数组上进行滤波的区别在于,只要输入不同,结果将有所不同。 ??‍♂️

除此之外,还有其他后果取决于您是否通过累加器或当前值进行过滤?这会在其他情况下引发错误吗?

幸运的是,您无需担心任何错误。但是,值得注意的是,函数的第二个版本比第一个版本~10% faster。我想这纯粹是偶然的。不同的测试数据集可能会产生不同的性能结果。

答案 1 :(得分:0)

在示例1中,当您合并两个列表时,请确保acc累加器将不包含curr ent中的任何元素。

另一方面,在示例2中,请确保curr ent不包含acc累加器中已经存在的任何元素。

区别在于元素显示的最终顺序


我认为这两个示例效率不高,因为它们都涉及O(n2)时间复杂度,因为您要嵌套迭代。正如其他人所说,第二个可能性能更高,因为嵌套迭代将在大概比累加器短的块上进行。


我宁愿这样写:

const union = (...tuples) => Array.from(
  new Set(
    tuples.flatMap(n => n),
  )
);



console.log(
  union([1, 10, 15, 20], [5, 88, 1, 7], [1, 10, 15, 5]),
);