簡體   English   中英

通過 object 屬性從數組中刪除對象

[英]remove objects from array by object property

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

如何通過匹配 object 屬性從陣列中刪除 object?

請僅使用本機 JavaScript。

我在使用拼接時遇到問題,因為每次刪除長度都會減少。 在原始索引上使用克隆和拼接仍然會給您帶來長度減少的問題。

我假設你使用了這樣的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));

您可以通過其屬性之一刪除項目,而無需使用任何 3rd 方庫,如下所示:

var removeIndex = array.map(item => item.id).indexOf("abc");

~removeIndex && array.splice(removeIndex, 1);

使用 lodash/下划線:

如果要修改現有數組本身,那么我們必須使用splice 這是使用下划線/lodash 的findWhere的更好/可讀的方法:

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)

關於 findIndex及其瀏覽器兼容性

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

根據給定數組中的 id 刪除對象;

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

如果您只想從現有數組中刪除它而不是創建一個新數組,請嘗試:

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

通過遞減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;
});

使用 Set 和 ES5 過濾器檢查一下。

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

這是 JsFiddle: https ://jsfiddle.net/jsq0a0p1/1/

請只使用原生 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' } ]

根據ECMA-262 中 'Array.prototype.reduceRight' 的定義

reduceRight 不會直接改變調用它的對象,但該對象可能會通過調用 callbackfn 來改變

所以這是reduceRight的有效用法。

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

如果您喜歡簡短且自我描述的參數,或者您不想使用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)

帶過濾器和 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));

您可以使用filter 如果條件為真,此方法總是返回元素。 因此,如果您想按 id 刪除,則必須保留所有與給定 id 不匹配的元素。 下面是一個例子:

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

一個非常簡短的方法是:

for (i = 0; i < listToDelete.length; i++) {
        arrayOfObjects = arrayOfObjects.filter((e) => e.id !== listToDelete[i])
    }

不正確的方式

首先,任何建議使用filter的答案實際上都不會刪除該項目。 這是一個快速測試:

var numbers = [1, 2, 2, 3];
numbers.filter(x => x === 2);
console.log(numbers.length);

在上面, numbers數組將保持不變(不會刪除任何內容)。 filter方法返回一個新數組,其中包含滿足條件x === 2的所有元素,但原始數組保持不變。

當然你可以這樣做:

var numbers = [1, 2, 2, 3];
numbers = numbers.filter(x => x === 2);
console.log(numbers.length);

但這只是將一個新數組分配給numbers


從數組中刪除項目的正確方法

正確的方法之一,不止1,是按照以下方式進行。 請記住,此處的示例故意包含重復項,因此可以考慮刪除重復項。

var numbers = [1, 2, 2, 3];

// Find all items you wish to remove
// If array has objects, then change condition to x.someProperty === someValue
var numbersToRemove = numbers.filter(x => x === 2);

// Now remove them
numbersToRemove.forEach(x => numbers.splice(numbers.findIndex(n => n === x), 1));

// Now check (this is obviously just to test)
console.log(numbers.length);
console.log(numbers);

現在您會注意到length返回 2,表示數組中只剩下數字 1 和 3。


在你的情況下

具體回答你的問題是這樣的:

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

這是答案:

listToDelete.forEach(x => arrayOfObjects.splice(arrayOfObjects.findIndex(n => n.id === x), 1));

var apps = [{id:34,name:'My App',another:'thing'},{id:37,name:'My New App',another:'things'}]

var removeIndex = apps.map(function(item) { return item.id; }).indexOf(37)

apps.splice(removeIndex, 1);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM