我有一个 Javascript 数组,我想根据每个元素上调用的函数是返回true
还是false
. 本质上,这是一个array.filter
,但我还想手头有被过滤掉的元素。
目前,我的计划是array.forEach
在每个元素上使用和调用谓词函数。根据这是对还是错,我会将当前元素推送到两个新数组之一。有没有更优雅或更好的方法来做到这一点?例如array.filter
,在它返回之前将元素推送到另一个数组的地方false
?
我有一个 Javascript 数组,我想根据每个元素上调用的函数是返回true
还是false
. 本质上,这是一个array.filter
,但我还想手头有被过滤掉的元素。
目前,我的计划是array.forEach
在每个元素上使用和调用谓词函数。根据这是对还是错,我会将当前元素推送到两个新数组之一。有没有更优雅或更好的方法来做到这一点?例如array.filter
,在它返回之前将元素推送到另一个数组的地方false
?
在 ES6 中,您可以通过 reduce 使用扩展语法:
function partition(array, isValid) {
return array.reduce(([pass, fail], elem) => {
return isValid(elem) ? [[...pass, elem], fail] : [pass, [...fail, elem]];
}, [[], []]);
}
const [pass, fail] = partition(myArray, (e) => e > 5);
或者在一行上:
const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);
您可以使用lodash.partition
var users = [
{ 'user': 'barney', 'age': 36, 'active': false },
{ 'user': 'fred', 'age': 40, 'active': true },
{ 'user': 'pebbles', 'age': 1, 'active': false }
];
_.partition(users, function(o) { return o.active; });
// → objects for [['fred'], ['barney', 'pebbles']]
// The `_.matches` iteratee shorthand.
_.partition(users, { 'age': 1, 'active': false });
// → objects for [['pebbles'], ['barney', 'fred']]
// The `_.matchesProperty` iteratee shorthand.
_.partition(users, ['active', false]);
// → objects for [['barney', 'pebbles'], ['fred']]
// The `_.property` iteratee shorthand.
_.partition(users, 'active');
// → objects for [['fred'], ['barney', 'pebbles']]
R.partition(R.contains('s'), ['sss', 'ttt', 'foo', 'bars']);
// => [ [ 'sss', 'bars' ], [ 'ttt', 'foo' ] ]
R.partition(R.contains('s'), { a: 'sss', b: 'ttt', foo: 'bars' });
// => [ { a: 'sss', foo: 'bars' }, { b: 'ttt' } ]
我想到了这个小家伙。它用于您描述的每一个和所有内容,但在我看来它看起来干净简洁。
//Partition function
function partition(array, filter) {
let pass = [], fail = [];
array.forEach((e, idx, arr) => (filter(e, idx, arr) ? pass : fail).push(e));
return [pass, fail];
}
//Run it with some dummy data and filter
const [lessThan5, greaterThanEqual5] = partition([0,1,4,3,5,7,9,2,4,6,8,9,0,1,2,4,6], e => e < 5);
//Output
console.log(lessThan5);
console.log(greaterThanEqual5);
您可以使用 reduce :
function partition(array, callback){
return array.reduce(function(result, element, i) {
callback(element, i, array)
? result[0].push(element)
: result[1].push(element);
return result;
}, [[],[]]
);
};
更新。使用 ES6 语法,您还可以使用递归(已更新以避免在每次迭代时创建新数组):
function partition([current, ...tail], f, left = [], right = []) {
if(current === undefined) {
return [left, right];
}
if(f(current)) {
left.push(current);
return partition(tail, f, left, right);
}
right.push(current);
return partition(tail, f, left, right);
}
这听起来与Ruby 的Enumerable#partition
方法非常相似。
如果函数不能产生副作用(即它不能改变原始数组),那么没有比迭代每个元素并将元素推送到两个数组之一更有效的方法来分区数组。
话虽如此,创建一个方法Array
来执行这个功能可以说是更“优雅” 。在这个例子中,过滤器函数在原始数组的上下文中执行(即,this
将是原始数组),它接收元素和元素的索引作为参数(类似于jQuery 的each
方法):
Array.prototype.partition = function (f){
var matched = [],
unmatched = [],
i = 0,
j = this.length;
for (; i < j; i++){
(f.call(this, this[i], i) ? matched : unmatched).push(this[i]);
}
return [matched, unmatched];
};
console.log([1, 2, 3, 4, 5].partition(function (n, i){
return n % 2 == 0;
}));
//=> [ [ 2, 4 ], [ 1, 3, 5 ] ]