在javascript中链接过滤器函数的好方法

eat*_*000 7 javascript higher-order-functions

我有大量的json对象数组,我需要根据多个用户选择输入进行过滤.目前我正在将过滤器功能链接在一起,但我感觉这很可能不是最有效的方法.

目前我这样做:

var filtered = data.filter(function(data) {
    return Conditional1
  })
  .filter(function(data) {
    return Conditional2
  })
  .filter(function(data) {
    return Conditional3
  }) etc...;
Run Code Online (Sandbox Code Playgroud)

虽然(我认为)每次迭代'数据'可能会更少,但我想知道更好的做法是做这样的事情:

var condition1 = Conditional1
var condition2 = Conditional2
var condition3 = Conditional3
etc...

var filtered = data.filter(function(data) {
  return condition1 && condition2 && condition3 && etc...
});
Run Code Online (Sandbox Code Playgroud)

我已经研究了多个高阶函数链,特别是过滤函数 - 但是我没有看到任何关于最佳实践的东西(或者不好的做法,也没有定时和比较我建议的两个).

在一个具有大数据集和许多条件的用例中(我认为它们都相当容易阅读)?

或者也许有一种更有效的方式我缺少(但仍使用高阶函数).

nul*_*ube 22

有趣的问题

data = new Array(111111).fill().map((a,n) => n);

const f1 = (a) => a % 2;
const f2 = (a) => a % 5;
const f3 = (a) => a > 347;
const filters = [f1, f2, f3];

// 1
t1 = performance.now();
res = data.filter(a=>a%2).filter(a=>a%5).filter(a=>a>347);
t2 = performance.now();
console.log("1) took " + (t2-t1) + " milliseconds.");
// 2
t1 = performance.now();
res = data.filter(a=>a%2 && a%5 && a>347);
t2 = performance.now();
console.log("2) took " + (t2-t1) + " milliseconds.");
// 3
t1 = performance.now();
res = filters.reduce((d, f) => d.filter(f) , data)
t2 = performance.now();
console.log("3) took " + (t2-t1) + " milliseconds.");
// 4
t1 = performance.now();
res = data.filter(v => filters.every(f => f(v)))
t2 = performance.now();
console.log("4) took " + (t2-t1) + " milliseconds.");
Run Code Online (Sandbox Code Playgroud)

还记得在 for 循环中,例如在两个循环的情况下,一个 3000 和一个 7 然后:3000x7 > 7x3000 时间测量。

  • 我希望这个答案成为最佳答案。 (3认同)

Jos*_*eph 11

将过滤器函数存储在数组中,并array.reduce()遍历每个过滤器,然后将其应用于数据。即使没有更多数据要过滤,也要以遍历所有这些为代价。

const data = [...]
const filters = [f1, f2, f3, ...]
const filteredData = filters.reduce((d, f) => d.filter(f) , data)
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用array.every()。这采用相反的方法,遍历数据,并检查是否所有过滤器都适用。array.every()一项返回时,返回false false

const data = [...]
const filters = [f1, f2, f3, ...]
const filteredData = data.filter(v => filters.every(f => f(v)))
Run Code Online (Sandbox Code Playgroud)

两者分别类似于您的第一个和第二个样本。唯一的区别是它不会对过滤器或条件进行硬编码。


the*_*eep 1

如果您将其视为“for 循环”优化问题,您可以看到原始方法会导致多次迭代列表。

第二种方法会将迭代减少为一次。

之后,您只需寻找快速确定项目是否通过测试的最佳方法即可。