オブジェクトプロパティによって配列からオブジェクトを削除する


138
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のみを使用してください。

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


1
逆方向にループすると、長さの変更の問題が修正されます
Ian

1
オブジェクト配列からアイテムを削除する標準的な適切な方法がないのはとても残念です。非常に多くのサードパーティスクリプトがあるのも不思議ではありません。それは基本的なことです。
ギタラス

回答:


155

あなたは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));

79

次のようなサードパーティのライブラリを使用せずに、そのプロパティの1つでアイテムを削除できます。

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

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

1
これは本当にエレガントな答えです。
Scott Silvi

もう1つ欲しいのは、配列内のすべてのオブジェクトに個別のボタンがあることです。クリックした配列ボタンの特定のオブジェクトを削除したい場合、別のセカンダリ配列に移動する必要があります。どうやってするの 。角度のあるjs ng-repeatを使用してアイテムを生成しました。あなたは私を助けることができます
Thilak Raj '21 / 01/16

とても素敵でエレガントなアプローチ。賞賛!注意が必要なことは1つだけです。必要なインデックスがマップ配列で見つからない場合、-1を返します。したがって、スプライスは最後の要素を削除します。
2016

15
または、最後の行のチルダで混乱した場合、次のようにわかりやすくなります。(removeIndex> = 0)&& array.splice(removeIndex、1);
wojjas

1
@parliament-あなたの例のチルダに関するドキュメントはありますか?私はこれを見たことがありません。
webdad3 2018

43

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

既存の配列自体を変更する場合は、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以降

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

ES5以降ではfindIndex、配列にメソッドがあるため、lodash / underscoreがなくても簡単です

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

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

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


オブジェクトの配列内のすべてのアイテムを削除する方法はありますが、コールバックも必要です
Muhaimin

あなたは..あなたは配列からオブジェクトを削除するには上記のコードを使用することができ、同様にコールバックによって何を意味しています
ラーフルR.

1
良いですね。これを私のツールベルトに追加します
abyrne85

もう1つ欲しいのは、配列内のすべてのオブジェクトに個別のボタンがあることです。クリックした配列ボタンの特定のオブジェクトを削除したい場合、別のセカンダリ配列に移動する必要があります。どうやってするの 。角度のあるjs ng-repeatを使用してアイテムを生成しました。あなたは私を助けることができます
Thilak Raj '21 / 01/16

1
このES5の提案をitems.splice(items.findIndex(i => i.id === "abc"), 1)
気に入ってください。

27

findIndexは、最新のブラウザーで機能します。

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

index = -1の場合にコードが大文字と小文字を区別しないことを除いて、私はこの現代的な答えが好きです
rmcsharry

2
他の人に比べて非常にシンプルな答えでうまくいきます。
2017年

シンプルでありながら強力なアクセス
シェリー

15

指定された配列のIDでオブジェクトを削除するには、

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

10

既存のアレイからそれを削除したいだけで、新しいアレイを作成したくない場合は、以下を試してください。

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

7
この回答には下線ライブラリが必要です
JoshuaDavid

2
要素が見つからない場合、_。indexOfは-1 => items.splice(-1,1)
user1441287

6

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


4

ネイティブ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


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関数のparamにインデックスを送信します。この単純なコードは、魅力のように機能します。

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

1
Thnaksこれは多くの助けとなりました:)
RAJESH KUMAR ARUMUGAM

1

フィルターと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));

0

短くて自己記述的なパラメータが好きな場合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)

-1

使用できますfilter。条件が真の場合、このメソッドは常に要素を返します。したがって、IDで削除する場合は、指定したIDと一致しないすべての要素を保持する必要があります。次に例を示します。

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.