Hapus semua elemen yang ada di array lain


222

Saya mencari cara yang efisien untuk menghapus semua elemen dari array javascript jika mereka ada di array lain.

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

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

Saya ingin beroperasi di myArray agar tetap seperti ini: ['a', 'd', 'e', 'f']

Dengan jQuery, saya menggunakan grep()dan inArray(), yang berfungsi dengan baik:

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

Apakah ada cara javascript murni untuk melakukan ini tanpa perulangan dan splicing?




1
kemungkinan duplikat Bisakah Anda menghapus satu array dari yang lain dalam javascript atau jquery - Anda tidak bisa terlalu memperhatikan saran yang dibuat ketika Anda menulis pertanyaan
mplungjan

Tidak peduli apa, itu akan selalu melibatkan pengulangan pada tingkat tertentu.
Blue Skies

Jika Anda benar-benar ingin menjadi "efisien", Anda tidak akan menggunakan metode tipe fungsional seperti .filter(). Sebagai gantinya Anda akan menggunakan forloop. Anda dapat menghindari .splice()jika pesanan asli tidak perlu dipertahankan. Atau ada cara untuk membuat .splice()lebih efisien jika Anda berpikir akan ada banyak item untuk dihapus.
Blue Skies

Jawaban:


379

Gunakan Array.filter()metode:

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

Peningkatan kecil, karena dukungan browser untuk Array.includes()telah meningkat:

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

Adaptasi berikutnya menggunakan fungsi panah :

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

23
OP: Jika Anda menggunakan Underscore.js ada .difference()yang pada dasarnya melakukan ini.
Bill Criswell

Apa yang saya cari. Terima kasih. @ BillCriswell, saya akan memeriksa garis bawah.
Ketuk

1
@AlecRust Konversi semua elemen toRemove()ke huruf besar dan ubah panggilan balik dari elmenjadi el.toUpperCase().
Sirko

5
atau lebih pendek:myArray = myArray.filter( el => !toRemove.includes( el ) );
538ROMEO

1
bukankah urutan ini n ^ 2?
Frazer Kirkman

34

The filterMetode harus melakukan trik:

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

Jika toRemovearray Anda besar, pola pencarian semacam ini bisa jadi tidak efisien. Akan lebih berkinerja untuk membuat peta sehingga pencarian O(1)lebih daripada 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

Jika Anda menggunakan berbagai objek. Maka kode di bawah ini harus melakukan keajaiban, di mana properti objek akan menjadi kriteria untuk menghapus item duplikat.

Dalam contoh di bawah ini, duplikat telah dihapus dengan membandingkan nama setiap item.

Coba contoh ini. 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 set dapat digunakan untuk menghitung elemen yang berbeda dari dua array:

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

Saya baru saja menerapkan sebagai:

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

Digunakan sebagai:

myArray.exclude(toRemove);

1
Ini bukan praktik yang baik untuk memperluas prototypesObjek asli, seperti itu Array. Itu bisa memiliki konflik jangka panjang dengan perkembangan bahasa di masa depan ( lihat flattenkasusnya )
Marco

6

Jika Anda tidak dapat menggunakan hal-hal ES5 baru seperti itu filtersaya pikir Anda terjebak dengan dua loop:

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

filter bukan "hal HTML5 baru"
goofballLogic

Saya seharusnya menulis "ES5 stuff". Itu tidak tersedia dengan ES3
MarcoL

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

Maukah Anda menambahkan beberapa penjelasan tentang pertanyaan yang diterima dengan baik itu?
harmonika141

1
Saya mencari solusi untuk masalah itu dan baru saja menemukannya, sangat mengagumkan. Terima kasih banyak!
Tarvo Mäesepp

5

Sekarang dalam rasa one-liner:

console.log(['a', 'b', 'c', 'd', 'e', 'f', 'g'].filter(x => !~['b', 'c', 'g'].indexOf(x)))

Mungkin tidak berfungsi di browser lama.


3

Anda dapat menggunakan _.differenceBy dari lodash

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

Contoh kode di sini: CodePen


Bagaimana jika atribut bersarang di dalam objek? Tes sesuatu seperti dalam kasus Anda {name: 'deepak', tempat: 'bangalore', bersarang: {test: 1}}
Charith Jayasanka

2

Bagaimana dengan yang paling sederhana:

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
Ingatlah bahwa includesitu tidak tersedia sebelum ES7.
Greg

0

Cara yang tepat untuk menghapus semua elemen yang terdapat dalam array lain adalah dengan membuat array sumber objek yang sama dengan menghapus hanya elemen:

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

Atau yang setara dengan CoffeeScript:

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

Pengujian di dalam alat dev krom:

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 benar

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

Menggunakan kerangka kerja Angular adalah cara terbaik untuk menjaga pointer ke objek sumber saat Anda memperbarui koleksi tanpa jumlah besar pengamat dan memuat ulang.


Jawaban ini buruk karena membatalkan praktik terbaik. Secara khusus, jangan pernah memodifikasi objek yang tidak Anda miliki. Dalam hal ini, Anda memodifikasi objek Array, yang merupakan no-no besar.
Web hybrid dev

0

Saya membangun logika tanpa menggunakan metode bawaan, beri tahu saya optimasi atau modifikasi apa pun. Saya diuji dalam editor JS itu berfungsi dengan baik.

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;
        }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.