【问题标题】:what is the difference between filtering on accumulator/current in reduce methodreduce方法中对累加器/电流进行滤波有什么区别
【发布时间】:2020-05-10 10:03:24
【问题描述】:

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 则相反。除此之外,如果您通过累加器或当前值过滤,它们是否还有其他后果?这会在不同的上下文中引发错误吗?

【问题讨论】:

    标签: javascript arrays function functional-programming reduce


    【解决方案1】:

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

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

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

    现在我们需要运行每个版本的函数,看看每个阶段的输出是什么。

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

    示例 A

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

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

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

    第一次执行

    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) 并删除累加器中已经存在的所有项目 (@987654340 @)。然后我们将该列表添加到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,而不是第一个版本。我猜这纯粹是间接的。不同的测试数据集可能会产生不同的性能结果。

    【讨论】:

      【解决方案2】:

      在示例1 中,当您连接这两个列表时,请确保accumulator 不会包含来自current 的任何元素。

      另一方面,在示例2 中,您要确保current 不会包含任何已存在于accumulator 中的元素。

      不同之处在于元素出现的最终顺序


      我认为这两个示例都没有效率,因为它们都涉及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]),
      );

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-01-27
        • 1970-01-01
        • 1970-01-01
        • 2014-02-27
        • 2014-02-09
        相关资源
        最近更新 更多