178
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 のみでお願いします。

削除するたびに長さが短くなるため、スプライスの使用に問題があります。元のインデックスでクローンとスプライシングを使用すると、長さが短くなるという問題が残ります。

4

13 に答える 13

175

このようなものを使用したと思います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));
于 2013-05-10T22:39:48.900 に答える
73

ロダッシュ/アンダースコア付き:

既存の配列自体を変更したい場合は、spliceを使用する必要があります。これは、アンダースコア/ロダッシュの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以上

(ロダッシュ/アンダースコアなし)

ES5 以降ではfindIndex配列にメソッドがあるため、lodash/underscore を使用しない方が簡単です

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

(ES5 はほとんどすべてのモーデン ブラウザでサポートされています)

findIndexとそのブラウザの互換性について

于 2014-03-12T16:01:30.683 に答える
34

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);
于 2016-08-25T05:16:16.857 に答える
2
var arrayOfObjects = [{id:'abc',name:'oh'}, // delete me
                      {id:'efg',name:'em'}, // delete me
                      {id:'hij',name:'ge'}] // all that should remain

あなたの答えによると、このようになります。特定のオブジェクトをクリックすると、delete me 関数のパラメーターにインデックスが送信されます。この単純なコードは魅力的に機能します。

function deleteme(i){
    if (i > -1) {
      arrayOfObjects.splice(i, 1);
    }
}
于 2017-11-25T08:03:19.963 に答える