別の配列に含まれるすべての要素を削除する


222

それらが別の配列に存在する場合、JavaScript配列からすべての要素を削除する効率的な方法を探しています。

// If I have this array:
var myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];

// and this one:
var toRemove = ['b', 'c', 'g'];

myArrayを操作して、この状態のままにしておきます。 ['a', 'd', 'e', 'f']

jQueryでは、私はgrep()and を使用しinArray()ています。

myArray = $.grep(myArray, function(value) {
    return $.inArray(value, toRemove) < 0;
});

ループやスプライシングなしでこれを行う純粋なJavaScriptの方法はありますか?




1
可能性のある重複した缶は、あなたはjavascriptやjqueryの中から別の配列を削除する -あなたは質問を書いたときに作られた提案に多くの注目を支払っていることはできません
mplungjan

何があっても、それは常にあるレベルでのループを伴います。
青い空

本当に「効率的」にしたい場合は、関数型メソッドを使用しないでください.filter()。代わりに、forループを使用します。.splice()元の順序を維持する必要がない場合は、回避できます。または.splice()、削除するアイテムが多数あると思われる場合は、より効率的にする方法があります。
Blue Skies

回答:


379

次のArray.filter()方法を使用します。

myArray = myArray.filter( function( el ) {
  return toRemove.indexOf( el ) < 0;
} );

ブラウザのサポートArray.includes()が増加したため、小さな改善:

myArray = myArray.filter( function( el ) {
  return !toRemove.includes( el );
} );

矢印関数を使用した次の適応:

myArray = myArray.filter( ( el ) => !toRemove.includes( el ) );

23
OP:あなたが使用している場合Underscore.jsをあります.difference()基本的にこれを実行しています。
Bill Criswell、2013年

まさに私が探していたもの。ありがとうございました。@BillCriswell、下線をチェックします。
2013年

1
@AlecRustのすべての要素を大文字に変換toRemove()し、コールバックをからelに変更しますel.toUpperCase()
Sirko

5
以下:myArray = myArray.filter( el => !toRemove.includes( el ) );
538ROMEO

1
この次数はn ^ 2ではありませんか?
Frazer Kirkman

34

filterこの方法は、トリックを行う必要があります。

const myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
const toRemove = ['b', 'c', 'g'];

// ES5 syntax
const filteredArray = myArray.filter(function(x) { 
  return toRemove.indexOf(x) < 0;
});

toRemove配列が大きい場合、この種のルックアップパターンは非効率になる可能性があります。ルックアップがO(1)ではなくマップになるようにマップを作成すると、パフォーマンスが向上しますO(n)

const toRemoveMap = toRemove.reduce(
  function(memo, item) {
    memo[item] = memo[item] || true;
    return memo;
  },
  {} // initialize an empty object
);

const filteredArray = myArray.filter(function (x) {
  return toRemoveMap[x];
});

// or, if you want to use ES6-style arrow syntax:
const toRemoveMap = toRemove.reduce((memo, item) => ({
  ...memo,
  [item]: true
}), {});

const filteredArray = myArray.filter(x => toRemoveMap[x]);

24

オブジェクトの配列を使用している場合。次に、以下のコードが魔法のように動作するはずです。オブジェクトプロパティは、重複するアイテムを削除するための基準になります。

以下の例では、各アイテムの名前を比較して重複が削除されています。

この例を試してください。http://jsfiddle.net/deepak7641/zLj133rh/

var myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
var toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];

for( var i=myArray.length - 1; i>=0; i--){
 	for( var j=0; j<toRemove.length; j++){
 	    if(myArray[i] && (myArray[i].name === toRemove[j].name)){
    		myArray.splice(i, 1);
    	}
    }
}

alert(JSON.stringify(myArray));



11

ECMAScript 6セットは、2つの配列の異なる要素を計算するために使用できます。

const myArray = new Set(['a', 'b', 'c', 'd', 'e', 'f', 'g']);
const toRemove = new Set(['b', 'c', 'g']);

const difference = new Set([...myArray].filter((x) => !toRemove.has(x)));

console.log(Array.from(difference)); // ["a", "d", "e", "f"]


8

私は次のように実装しました:

Array.prototype.exclude = function(list){
        return this.filter(function(el){return list.indexOf(el)<0;})
}

使用:

myArray.exclude(toRemove);

1
prototypesなどのネイティブオブジェクトを拡張することはお勧めしませんArray。これは、言語の将来の発展と長期的に対立する可能性があります(事例を参照flatten
MarcoL 2018年

6

このような新しいES5を使用できない場合filter、2つのループに行き詰まっていると思います。

for( var i =myArray.length - 1; i>=0; i--){
  for( var j=0; j<toRemove.length; j++){
    if(myArray[i] === toRemove[j]){
      myArray.splice(i, 1);
    }
  }
}

フィルターは「新しいHTML5もの」ではありません
goofballLogic '11年

「ES5関連」と書けばよかった。ES3では使用できませんでした
MarcoL 2016年

6
var myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
var toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];



myArray = myArray.filter(ar => !toRemove.find(rm => (rm.name === ar.name && ar.place === rm.place) ))

そんな好評の質問に説明をお願いします。
harmonica141

1
私は問題の解決策を何時間も検索しましたが、それを見つけました、ただ素晴らしいです。どうもありがとうございました!
TarvoMäesepp19年


3

あなたはlodashから_.differenceBy を使うことができます

const myArray = [
  {name: 'deepak', place: 'bangalore'}, 
  {name: 'chirag', place: 'bangalore'}, 
  {name: 'alok', place: 'berhampur'}, 
  {name: 'chandan', place: 'mumbai'}
];
const toRemove = [
  {name: 'deepak', place: 'bangalore'},
  {name: 'alok', place: 'berhampur'}
];
const sorted = _.differenceBy(myArray, toRemove, 'name');

ここにサンプルコード:CodePen


属性がオブジェクト内にネストされている場合はどうなりますか?あなたの場合のような何かのテスト{name: 'deepak'、place: 'bangalore'、nested:{test:1}}
Charith Jayasanka

2

最も簡単な方法はどうですか:

var myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g'];
var toRemove = ['b', 'c', 'g'];

var myArray = myArray.filter((item) => !toRemove.includes(item));
console.log(myArray)


2
覚えておいてくださいincludesES7の前には使用できません。
グレッグ

0

別の配列に含まれるすべての要素を削除する適切な方法は、要素のみを削除することにより、ソース配列を同じオブジェクトにすることです。

Array.prototype.removeContained = function(array) {
  var i, results;
  i = this.length;
  results = [];
  while (i--) {
    if (array.indexOf(this[i]) !== -1) {
      results.push(this.splice(i, 1));
    }
  }
  return results;
};

または、CoffeeScriptの同等の機能:

Array.prototype.removeContained = (array) ->
  i = @length
  @splice i, 1 while i-- when array.indexOf(@[i]) isnt -1

Chrome開発ツール内のテスト:

19:33:04.447 a = 1
19:33:06.354 b = 2
19:33:07.615 c = 3
19:33:09.981 arr = [a、b、c]
19:33:16.460 arr1 = arr

19:33:20.317 arr1 === arr
19:33:20.331 true

19:33:43.592 arr.removeContained([a、c])
19:33:52.433 arr === arr1
19:33:52.438 true

Angularフレームワークの使用は、大量のウォッチャーとリロードなしでコレクションを更新するときに、ソースオブジェクトへのポインターを保持するための最良の方法です。


この回答は、ベストプラクティスを無効にするため、不適切です。具体的には、所有していないオブジェクトを変更しないでください。この例では、Arrayオブジェクトを変更していますが、これは大したことではありません。
ハイブリッドWeb

0

組み込みメソッドを使用せずにロジックを構築しています。最適化や変更について教えてください。JSエディターでテストしましたが、正常に動作しています。

var myArray = [
            {name: 'deepak', place: 'bangalore'},
            {name: 'alok', place: 'berhampur'},
            {name: 'chirag', place: 'bangalore'},
            {name: 'chandan', place: 'mumbai'},

        ];
        var toRemove = [

            {name: 'chirag', place: 'bangalore'},
            {name: 'deepak', place: 'bangalore'},
            /*{name: 'chandan', place: 'mumbai'},*/
            /*{name: 'alok', place: 'berhampur'},*/


        ];
        var tempArr = [];
        for( var i=0 ; i < myArray.length; i++){
            for( var j=0; j<toRemove.length; j++){
                var toRemoveObj = toRemove[j];
                if(myArray[i] && (myArray[i].name === toRemove[j].name)) {
                    break;
                }else if(myArray[i] && (myArray[i].name !== toRemove[j].name)){
                        var fnd = isExists(tempArr,myArray[i]);
                        if(!fnd){
                            var idx = getIdex(toRemove,myArray[i])
                            if (idx === -1){
                                tempArr.push(myArray[i]);
                            }

                        }

                    }

                }
        }
        function isExists(source,item){
            var isFound = false;
            for( var i=0 ; i < source.length; i++){
                var obj = source[i];
                if(item && obj && obj.name === item.name){
                    isFound = true;
                    break;
                }
            }
            return isFound;
        }
        function getIdex(toRemove,item){
            var idex = -1;
            for( var i=0 ; i < toRemove.length; i++){
                var rObj =toRemove[i];
                if(rObj && item && rObj.name === item.name){
                    idex=i;
                    break;
                }
            }
            return idex;
        }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.