[英]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.