[英]JavaScript array: is there a method that is a cross between splice and filter?
I have an array of objects, and want to: 我有一组对象,并且想要:
I don't know in advance where these objects are. 我事先不知道这些对象在哪里。 To recognize them, I need to use a function that queries their properties.
为了识别它们,我需要使用一个查询其属性的函数。 It makes sense to retrieve the removed objects in a second array.
在第二个数组中检索删除的对象很有意义。
I had hoped to find a native method like filter
or splice
that would do this. 我曾希望找到一个可以执行此操作的本机方法,例如
filter
或splice
。 Here's what I've come up with as a solution: 这是我想出的解决方案:
if (!Array.prototype.cherrypick) {
Array.prototype.cherrypick = function(fn) {
let basket = []
let ii = this.length
let item
for ( ; ii-- ; ) {
item = this[ii]
if (fn(item)) {
basket.unshift(item)
this.splice(ii, 1)
}
}
return basket
}
}
Have I missed something? 我错过了什么吗? Is there a native method that does this already?
是否已有本机方法? Is my solution unsound in some way?
我的解决方案有些不完善吗?
Methods such as Array.filter()
returns a new array instead of changing the original array. 诸如
Array.filter()
返回一个新数组,而不是更改原始数组。
You can create a partition method using Array.reduce()
that will return two arrays - those that passed the predicate, and those that failed: 您可以使用
Array.reduce()
创建一个分区方法,该方法将返回两个数组-那些通过谓词的数组和那些失败的数组:
const partition = (predicate, arr) => arr.reduce((r, o) => { r[+!!predicate(o)].push(o); return r; }, [[], []]); const arr = [4, 8, 3, 10, 12]; const result = partition(n => n > 5, arr); console.log(result);
And you can use the partition logic with Array.splice()
to create the cherrypick
method: 您可以将分区逻辑与
Array.splice()
来创建cherrypick
方法:
if (!Array.prototype.cherrypick) { Array.prototype.cherrypick = function(predicate) { const [removedItems, items] = arr.reduce((r, o) => { r[+!!predicate(o)].push(o); return r; }, [[], []]); this.splice(0, arr.length, items); return removedItems; } } const arr = [4, 8, 3, 10, 12]; const removed = arr.cherrypick(n => n > 5); console.log('arr ', arr); console.log('removed ', removed);
Have I missed something?
我错过了什么吗? Is there a native method that does this already?
是否已有本机方法?
No, most native utility methods try not to mutate the array and instead return a new one. 不,大多数本机实用程序方法都尝试不改变数组,而是返回一个新数组。
Is my solution unsound in some way?
我的解决方案有些不完善吗?
Using splice
and unshift
repeatedly like you do is very inefficient. 像您一样反复使用
splice
和unshift
非常低效。 Better write 更好的写
if (typeof Array.prototype.cherrypick == "function")
console.warn("something already defines Array#cherrypick!");
Array.prototype.cherrypick = function(predicate) {
let removed = [];
for (let i=0, j=0; i<this.length; i++) {
const item = this[i];
if (fn(item)) {
removed.push(item);
} else {
this[j++] = item; // keep in array, but at new position
}
}
this.length = j; // removes rest
return removed;
};
Just filter twice: 只需过滤两次:
const picked = array.filter(fn);
array = array.filter((el, i, a) => !fn(el, i, a));
Use reduce as follows : 如下使用reduce:
array = [1,2,3,4,5,6,7];
fn = n => n % 3 == 0;
[array, picked] = array.reduce ( (r, el) => (r[+fn(el)].push (el), r), [[], []] )
Do you want something like this? 你想要这样的东西吗?
const basket = ['apple', 'banana', 'car'];
const filterMapBasket = basket
.filter(item => item !== 'car')
.map(item => {return { name: item }});
This will result the initial basket array of strings to be filtered and transformed to an array of objects. 这将导致初始的篮子字符串数组被过滤并转换为对象数组。
This will alter the source array in place removing items meeting some test, and return those items... 这将改变源数组的位置,删除满足某些测试条件的项目,然后返回这些项目...
Array.prototype.removeIf = function(fn) { let i = this.length; let removed = []; while (i--) { if (fn(this[i], i)) { removed.push(...this.splice(i, 1)); } } return removed; }; let a = [0,1,2,3,4,5]; let removed = a.removeIf(i => i%2); console.log(a); console.log(removed);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.