【问题标题】:remove objects from array by object property通过对象属性从数组中删除对象
【发布时间】:2013-05-05 16:46:14
【问题描述】:
var listToDelete = ['abc', 'efg'];

var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

如何通过匹配对象属性从数组中删除对象?

请只使用原生 JavaScript。

我在使用拼接时遇到问题,因为每次删除都会缩短长度。 在原始索引上使用克隆和拼接仍然会给您带来长度减少的问题。

【问题讨论】:

  • 向后循环应该可以解决长度变化问题
  • 很遗憾没有标准的正确方法从对象数组中删除项目。难怪有这么多第 3 方脚本。这是基本的东西。

标签: javascript


【解决方案1】:

我假设你使用了splice 类似的东西?

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
    }
}

修复该错误所需要做的就是在下一次减少i,然后(并且向后循环也是一种选择):

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) !== -1) {
        arrayOfObjects.splice(i, 1);
        i--;
    }
}

为避免线性时间删除,您可以在数组上写入要保留的数组元素:

var end = 0;

for (var i = 0; i < arrayOfObjects.length; i++) {
    var obj = arrayOfObjects[i];

    if (listToDelete.indexOf(obj.id) === -1) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

为了避免现代运行时中的线性时间查找,您可以使用哈希集:

const setToDelete = new Set(listToDelete);
let end = 0;

for (let i = 0; i < arrayOfObjects.length; i++) {
    const obj = arrayOfObjects[i];

    if (setToDelete.has(obj.id)) {
        arrayOfObjects[end++] = obj;
    }
}

arrayOfObjects.length = end;

可以封装在一个不错的函数中:

const filterInPlace = (array, predicate) => {
    let end = 0;

    for (let i = 0; i < array.length; i++) {
        const obj = array[i];

        if (predicate(obj)) {
            array[end++] = obj;
        }
    }

    array.length = end;
};

const toDelete = new Set(['abc', 'efg']);

const arrayOfObjects = [{id: 'abc', name: 'oh'},
                        {id: 'efg', name: 'em'},
                        {id: 'hij', name: 'ge'}];

filterInPlace(arrayOfObjects, obj => !toDelete.has(obj.id));
console.log(arrayOfObjects);

如果你不需要就地做,那就是Array#filter

const toDelete = new Set(['abc', 'efg']);
const newArray = arrayOfObjects.filter(obj => !toDelete.has(obj.id));

【讨论】:

    【解决方案2】:

    您可以通过其属性之一删除项目,而无需使用任何 3rd 方库,如下所示:

    var removeIndex = array.map(item => item.id).indexOf("abc");
    
    ~removeIndex && array.splice(removeIndex, 1);
    

    【讨论】:

    • 或者,如果您对最后一行的波浪号感到困惑,您可能会发现这更清楚: (removeIndex >= 0) && array.splice(removeIndex, 1);
    • 这个答案比选择的答案更快更优雅:jsben.ch/ld9op
    • @ZackLee:当然,对于 5/10 元素,它可能会更快。这是 50/100:jsben.ch/55g97
    • (另外,您可以跳过少数元素的集合构造,然后 it’s faster again,即使您缓存 id 数组也是如此。此外,这两种方法不会以相同的方式处理重复项。不是确定这是否重要。)
    【解决方案3】:

    带 lodash/下划线:

    如果你想修改现有数组本身,那么我们必须使用splice。这是使用 findWhere 的下划线/lodash 的更好/可读的方式:

    var items= [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'},
                      {id:'hij',name:'ge'}];
    
    items.splice(_.indexOf(items, _.findWhere(items, { id : "abc"})), 1);
    

    使用 ES5 或更高版本

    没有 lodash/下划线

    从 ES5 开始,我们在数组上有 findIndex 方法,因此没有 lodash/underscore 会更容易

    items.splice(items.findIndex(function(i){
        return i.id === "abc";
    }), 1);
    

    (几乎所有现代浏览器都支持 ES5)

    About findIndex,及其Browser compatibility

    【讨论】:

    • 如何删除对象数组中的所有项目,但我也需要回调
    • 回调是什么意思,你可以使用上面的代码从数组中删除对象..
    • 不错的一个。我将把它添加到我的工具带中
    • 喜欢这个 ES5 建议,因为它甚至可以用更短的方式编写 items.splice(items.findIndex(i =&gt; i.id === "abc"), 1)
    • 请小心。这不会删除数组中具有相同“id”的所有对象。
    【解决方案4】:

    findIndex 适用于现代浏览器:

    var myArr = [{id:'a'},{id:'myid'},{id:'c'}];
    var index = myArr.findIndex(function(o){
      return o.id === 'myid';
    })
    if (index !== -1) myArr.splice(index, 1);
    

    【讨论】:

    • 我喜欢这个现代的答案,除了你的代码在 index=-1 时没有捕捉到这种情况
    • 与其他人相比非常简单的答案并且工作得很好。
    • 简单而强大的asnwer
    【解决方案5】:

    通过给定数组中的 id 删除对象;

    const hero = [{'id' : 1, 'name' : 'hero1'}, {'id': 2, 'name' : 'hero2'}];
    //remove hero1
    const updatedHero = hero.filter(item => item.id !== 1);
    

    【讨论】:

    • filter() 将在找到第一个元素后继续过滤。
    【解决方案6】:

    如果您只想从现有数组中删除它而不创建新数组,请尝试:

    var items = [{Id: 1},{Id: 2},{Id: 3}];
    items.splice(_.indexOf(items, _.find(items, function (item) { return item.Id === 2; })), 1);
    

    【讨论】:

    • 注意这个答案需要 underscore
    • 我不建议这样做,因为如果找不到元素 _.indexOf 将返回 -1 => items.splice(-1,1)
    【解决方案7】:

    使用 Set 和 ES5 过滤器检查一下。

      let result = arrayOfObjects.filter( el => (-1 == listToDelete.indexOf(el.id)) );
      console.log(result);
    

    这里是 JsFiddle: https://jsfiddle.net/jsq0a0p1/1/

    【讨论】:

    • 完美运行!
    • 我认为最现代、最优雅的方法。
    【解决方案8】:

    通过递减i 反向循环以避免该问题:

    for (var i = arrayOfObjects.length - 1; i >= 0; i--) {
        var obj = arrayOfObjects[i];
    
        if (listToDelete.indexOf(obj.id) !== -1) {
            arrayOfObjects.splice(i, 1);
        }
    }
    

    或者使用filter:

    var newArray = arrayOfObjects.filter(function(obj) {
        return listToDelete.indexOf(obj.id) === -1;
    });
    

    【讨论】:

      【解决方案9】:

      请仅使用原生 JavaScript。

      作为替代的、更“功能性”的解决方案,在 ECMAScript 5 上工作,您可以使用:

      var listToDelete = ['abc', 'efg'];
      var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                            {id:'efg',name:'em'}, // delete me
                            {id:'hij',name:'ge'}]; // all that should remain
      
      arrayOfObjects.reduceRight(function(acc, obj, idx) {
          if (listToDelete.indexOf(obj.id) > -1)
              arrayOfObjects.splice(idx,1);
      }, 0); // initial value set to avoid issues with the first item and
             // when the array is empty.
      
      console.log(arrayOfObjects);
      [ { id: 'hij', name: 'ge' } ]
      

      根据the definition of 'Array.prototype.reduceRight' in ECMA-262

      reduceRight 不会直接改变调用它的对象但该对象可能会被回调函数的调用改变

      所以这是reduceRight 的有效用法。

      【讨论】:

        【解决方案10】:
        var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                              {id:'efg',name:'em'}, // delete me
                              {id:'hij',name:'ge'}] // all that should remain
        

        根据你的回答会是这样的。当您单击某个特定对象时,请发送参数中的索引以用于删除我功能。这个简单的代码会像魅力一样工作。

        function deleteme(i){
            if (i > -1) {
              arrayOfObjects.splice(i, 1);
            }
        }
        

        【讨论】:

          【解决方案11】:

          如果您喜欢简短且自我描述的参数,或者如果您不想使用 splice 并使用直接过滤器,或者如果您只是像我这样的 SQL 人员:

          function removeFromArrayOfHash(p_array_of_hash, p_key, p_value_to_remove){
              return p_array_of_hash.filter((l_cur_row) => {return l_cur_row[p_key] != p_value_to_remove});
          }
          

          还有一个示例用法:

          l_test_arr = 
          [
              {
                   post_id: 1,
                  post_content: "Hey I am the first hash with id 1"
              },
              {
                  post_id: 2,
                  post_content: "This is item 2"
              },
              {
                  post_id: 1,
                  post_content: "And I am the second hash with id 1"
              },
              {
                  post_id: 3,
                  post_content: "This is item 3"
              },
           ];
          
          
          
           l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 2); // gives both of the post_id 1 hashes and the post_id 3
           l_test_arr = removeFromArrayOfHash(l_test_arr, "post_id", 1); // gives only post_id 3 (since 1 was removed in previous line)
          

          【讨论】:

            【解决方案12】:

            带有过滤器和 indexOf

            withLodash = _.filter(arrayOfObjects, (obj) => (listToDelete.indexOf(obj.id) === -1));
            withoutLodash = arrayOfObjects.filter(obj => listToDelete.indexOf(obj.id) === -1);
            

            带有过滤器和包含

            withLodash = _.filter(arrayOfObjects, (obj) => (!listToDelete.includes(obj.id)))
            withoutLodash = arrayOfObjects.filter(obj => !listToDelete.includes(obj.id));
            

            【讨论】:

              【解决方案13】:

              您可以使用filter。如果条件为真,此方法总是返回元素。因此,如果您想按 id 删除,则必须保留所有与给定 id 不匹配的元素。这是一个例子:

              arrayOfObjects = arrayOfObjects.filter(obj => obj.id != idToRemove)

              【讨论】:

                猜你喜欢
                • 2015-04-08
                • 2019-11-17
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-29
                • 1970-01-01
                • 2021-09-11
                • 2020-04-28
                相关资源
                最近更新 更多