簡體   English   中英

具有多個條件的Array.filter

[英]Array.filter with more than one conditional

我有一個對象數組,我想根據條件篩選和分組。 困境的出現是因為我有多個條件,並希望將數組分成幾個數組。 第一個數組匹配第一個條件,第二個數組匹配第二個條件,...,以及包含所有不匹配任何條件的對象的最后一個數組。

想到這個問題的第一個解決方案是幾個.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答案的功能,並得到了這個。

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個數組的數組。 第一個包含與第一個條件匹配的所有對象,第二個包含與第二個條件匹配的對象,第二個包含與兩者中任何一個不匹配的對象。

這種方法的問題在於它僅限於兩個條件,因此只有三組對象。 這種方法實際上適用於我的特定情況,因為我只有兩個條件,但在需要兩個以上的情況下不可重復使用。

我希望能夠提供盡可能多的條件,並接收數量的數組以及一個不屬於任何組的對象的額外數組。

PS。 輸入和輸出不需要是數組,但我認為這更有意義。 該方法不必在.filter之后建模,它很可能是.map函數甚至是.reduce。 任何建議表示贊賞。

編輯:正如@slebetman所建議的那樣,如果答案允許代碼可組合性,那將會很棒。

嘗試這樣的事情:

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);

最終數組中的最后一個元素 - 不匹配的條目。

我們將使用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));

此解決方案涉及定義一個函數,您向其提供各種過濾器,這些函數返回一個函數,然后您可以使用該函數進行實際分組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM