JavaScript数组:拼接和过滤器之间是否有交叉的方法?

时间:2018-09-28 15:48:44

标签: javascript arrays filtering

我有一个对象数组,并且想要:

  1. 从数组中删除某些对象
  2. 第二步处理已移除的对象

我事先不知道这些物体在哪里。为了识别它们,我需要使用一个查询其属性的函数。在第二个数组中检索已删除的对象很有意义。

我曾经希望找到一种可以执行此操作的本机方法,例如filtersplice。这是我想出的解决方案:

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
  }
}

我错过了什么吗?是否已有本机方法?我的解决方案在某种程度上不正确吗?

6 个答案:

答案 0 :(得分:1)

诸如Array.filter()之类的方法将返回一个新数组,而不是更改原始数组。

您可以使用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);

您可以将分区逻辑与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);

答案 1 :(得分:1)

  

我错过了什么吗?是否已有本机方法?

否,大多数本机实用程序方法都尽量不对数组进行突变,而是返回一个新数组。

  

我的解决方案听起来有些奇怪吗?

像您一样反复使用spliceunshift效率很低。写得更好

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

答案 2 :(得分:0)

只需过滤两次:

const picked = array.filter(fn);
array = array.filter((el, i, a) => !fn(el, i, a));

答案 3 :(得分:0)

按如下方式使用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), [[], []] ) 

答案 4 :(得分:0)

您想要这样的东西吗?

const basket = ['apple', 'banana', 'car'];
const filterMapBasket = basket
                       .filter(item => item !== 'car')
                       .map(item => {return { name: item }});

这将导致初始的一篮子字符串数组被过滤并转换为对象数组。

答案 5 :(得分:0)

这将改变源数组的位置,删除满足某些测试条件的项目,并返回这些项目...

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