Javascript 用过滤器函数划分数组
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11731072/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dividing an array by filter function
提问by Mike Chen
I have a Javascript array that I would like to split into two based on whether a function called on each element returns true
or false
. Essentially, this is an array.filter
, but I'd like to also have on hand the elements that were filtered out.
我有一个 Javascript 数组,我想根据每个元素上调用的函数是返回true
还是false
. 本质上,这是一个array.filter
,但我还想手头有被过滤掉的元素。
Currently, my plan is to use array.forEach
and call the predicate function on each element. Depending on whether this is true or false, I will push the current element onto one of the two new arrays. Is there a more elegant or otherwise better way to do this? An array.filter
where the will push the element onto another array before it returns false
, for instance?
目前,我的计划是array.forEach
在每个元素上使用和调用谓词函数。根据这是对还是错,我会将当前元素推送到两个新数组之一。有没有更优雅或更好的方法来做到这一点?例如array.filter
,在它返回之前将元素推送到另一个数组的地方false
?
回答by braza
With ES6 you can make use of the spread syntax with reduce:
在 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);
Or on a single line:
或者在一行上:
const [pass, fail] = a.reduce(([p, f], e) => (e > 5 ? [[...p, e], f] : [p, [...f, e]]), [[], []]);
回答by Zoltan Kochan
You can use lodash.partition
您可以使用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' } ]
回答by Yaremenko Andrii
You can use reduce for it:
您可以使用 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;
}, [[],[]]
);
};
Update. Using ES6 syntax you also can do that using recursion:
更新。使用 ES6 语法,您也可以使用递归来做到这一点:
function partition([current, ...tail], f, [left, right] = [[], []]) {
if(current === undefined) {
return [left, right];
}
if(f(current)) {
return partition(tail, f, [[...left, current], right]);
}
return partition(tail, f, [left, [...right, current]]);
}
回答by Brandan
This sounds very similar to Ruby's Enumerable#partition
method.
这听起来与Ruby 的Enumerable#partition
方法非常相似。
If the function can't have side-effects (i.e., it can't alter the original array), then there's no more efficient way to partition the array than iterating over each element and pushing the element to one of your two arrays.
如果函数不能产生副作用(即它不能改变原始数组),那么没有比迭代每个元素并将元素推送到两个数组之一更有效的方法来分区数组。
That being said, it's arguably more "elegant" to create a method on Array
to perform this function. In this example, the filter function is executed in the context of the original array (i.e., this
will be the original array), and it receives the element and the index of the element as arguments (similar to jQuery's each
method):
话虽如此,创建一个方法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 ] ]
回答by UDrake
I came up with this little guy. It uses for each and all that like you described, but it looks clean and succinct in my opinion.
我想到了这个小家伙。它用于您所描述的所有内容,但在我看来它看起来干净简洁。
//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);
回答by codename-
In filter function you can push your false items into another variable outside function:
在过滤器函数中,您可以将错误项推送到函数外的另一个变量中:
var bad = [], good = [1,2,3,4,5];
good = good.filter(function (value) { if (value === false) { bad.push(value) } else { return true});
Of course value === false
need to be real comparasion ;)
当然value === false
需要真正的比较;)
But it do almost that same operation like forEach
. I think you should use forEach
for better code readability.
但它执行的操作几乎与forEach
. 我认为你应该使用forEach
更好的代码可读性。
回答by qwertymk
回答by Vereb
What about this?
那这个呢?
[1,4,3,5,3,2].reduce( (s, x) => { s[ x > 3 ].push(x); return s;} , {true: [], false:[]} )
Probably this is more efficient then the spread operator
可能这比传播运算符更有效
Or a bit shorter, but uglier
或者更短,但更丑
[1,4,3,5,3,2].reduce( (s, x) => s[ x > 3 ].push(x)?s:s , {true: [], false:[]} )
回答by Matsumoto Kazuya
Easy to read one.
轻松读一读。
const partition = (arr, condition) => {
const trues = arr.filter(el => condition(el));
const falses = arr.filter(el => !condition(el));
return [trues, falses];
};
// sample usage
const nums = [1,2,3,4,5,6,7]
const [evens, odds] = partition(nums, (el) => el%2 == 0)
回答by Andreas Gassmann
I ended up doing this because it's easy to understand (and fully typed with typescript).
我最终这样做是因为它很容易理解(并且完全用打字稿打字)。
const partition = <T>(array: T[], isValid: (element: T) => boolean): [T[], T[]] => {
const pass: T[] = []
const fail: T[] = []
array.forEach(element => {
if (isValid(element)) {
pass.push(element)
} else {
fail.push(element)
}
})
return [pass, fail]
}
// usage
const [pass, fail] = partition([1, 2, 3, 4, 5], (element: number) => element > 3)