具有多个条件

时间:2016-07-25 03:29:01

标签: javascript arrays loops

我有一个对象数组,我想根据条件筛选并分组。困境的出现是因为我有多个条件,并希望将数组分成几个数组。第一个数组匹配第一个条件,第二个数组匹配第二个条件,...,以及包含所有不匹配任何条件的对象的最后一个数组。

这个问题的第一个解决方案是几个.filter函数的形式......

var array = [{
  name: 'X',
  age: 18
}, {
  name: 'Y',
  age: 18
}, {
  name: 'Z',
  age: 20
}, {
  name: 'M',
  age: 20
}, {
  name: 'W',
  age: 5
}, {
  name: 'W',
  age: 10
}];
//objects with age 18
var matchedConditional1 = array.filter(function(x){
  return x.age === 18;
});
//objects with age 20
var matchedConditional2 = array.filter(function(x){
  return x.age === 20;
});
//objects with neither age 18 or 20
var matchedNoConditional = array.filter(function(x){
  return (x.age !== 18 && x.age !== 20);
});

但这似乎是多余的,根本不可重复使用。

所以我修改了Brendan's回答的功能,并得到了这个。

Array.prototype.group = function(f) {
  var matchedFirst = [],
      matchedSecond = [],
      unmatched = [],
      i = 0,
      l = this.length;
  for (; i < l; i++) {
    if (f.call(this, this[i], i)[0]) {
      matchedFirst.push(this[i]);
    } else if (f.call(this, this[i], i)[1]) {
      matchedSecond.push(this[i]);
    } else {
      unmatched.push(this[i]);
    }
  }
  return [matchedFirst, matchedSecond, unmatched];
};
var filteredArray = array.group(function(x){
  return [x.age === 18, x.age === 20];
});

此方法返回一个包含3个数组的数组。第一个包含与第一个条件匹配的所有对象,第二个包含与第二个条件匹配的对象,第二个包含与两个条件不匹配的对象。

这种方法的问题在于它仅限于两个条件,因此只有三组对象。这种方法实际上适用于我的特定情况,因为我只有两个条件,但在需要两个以上的情况下不可重用。

我希望能够提供尽可能多的条件并接收数量的数组以及包含不属于任何组的对象的额外数组。

聚苯乙烯。输入和输出不需要是数组,但我认为这更有意义。该方法不必在.filter之后建模,它很可能是.map函数甚至是.reduce。任何建议都表示赞赏。

编辑:正如@slebetman所建议的那样,如果答案允许代码可组合性,那将会很棒。

2 个答案:

答案 0 :(得分:2)

尝试这样的事情:

Array.prototype.groups = function(...conditions) {
  return this.reduce(
    (groups, entry) => {
      let indices = [];

      conditions.forEach((cond, i) => {
        if (cond(entry)) indices.push(i);
      });

      if (indices.length === 0) groups[groups.length - 1].push(entry);
      else indices.forEach(i => groups[i].push(entry));

      return groups
    }, 
    Array.apply(null, { length: conditions.length + 1})
      .map(e => [])
  );
}

在此解决方案中,如果条目与多个条件匹配,则它将显示在相应的组数中。

用法示例:array.groups(x => x.name === 'X', x => x.age === 18);

最终数组中的最后一个元素 - 不匹配的条目。

答案 1 :(得分:2)

我们将使用findIndex来查找匹配条件的索引,并将该元素放在输出的相应数组元素中:

function makeGrouper(...conditions) {

  return function(array) {
    // Make an array of empty arrays for each condition, plus one.
    var results = conditions.map(_ => []).concat([]);

    array.forEach(elt => {
      var condition = conditions.findIndex(condition => condition(elt));
      if (condition === -1) condition = conditions.length;
      results[condition].push(elt);
    });

    return results;
  };

}

或者,如果您是reduce

的粉丝
function makeGrouper(...conditions) {

  return function(array) {
    return array.reduce((results, elt) => {
      var condition = conditions.findIndex(condition => condition(elt));
      if (condition === -1) condition = conditions.length;
      results[condition].push(elt);
      return results;
    }, conditions.map(_ => []).concat([])));  
  };

}

用法:

const grouper = makeGrouper(
  elt => elt.age === 18,
  elt => elt.age === 20
);

console.log(grouper(data));

此解决方案涉及定义一个函数,您可以向其提供各种过滤器,这些函数返回一个函数,然后您可以使用该函数进行实际分组。