Usuń wszystkie elementy zawarte w innej tablicy

222

Szukam skutecznego sposobu usunięcia wszystkich elementów z tablicy javascript, jeśli są one obecne w innej tablicy.

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

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

Chcę operować myArray, aby pozostawić go w tym stanie: ['a', 'd', 'e', 'f']

W jQuery używam grep()i inArray(), co działa dobrze:

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

Czy istnieje czysty sposób javascript, aby to zrobić bez zapętlania i łączenia?

Kran
źródło
1
możliwy duplikat Usuń określony element z tablicy?
mplungjan
4
możliwy duplikat różnic w tablicy JavaScript
Pills Explosion Pills
1
możliwy duplikat Czy można usunąć jedną tablicę z drugiej w javascript lub jquery - nie można było zwrócić dużej uwagi na sugestie sformułowane podczas pisania pytania
mplungjan
Nie ważne co, zawsze będzie wymagało zapętlenia na pewnym poziomie.
Blue Skies
Jeśli naprawdę chcesz, aby był „wydajny”, nie będziesz używać metod typu funkcjonalnego, takich jak .filter(). Zamiast tego użyjesz forpętli. Można tego uniknąć, .splice()jeśli oryginalne zamówienie nie musi być utrzymywane. Lub istnieją sposoby na .splice()zwiększenie wydajności, jeśli uważasz, że będzie wiele rzeczy do usunięcia.
Blue Skies

Odpowiedzi:

379

Użyj Array.filter()metody:

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

Niewielkie ulepszenie, ponieważ Array.includes()wzrosła obsługa przeglądarki :

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

Następna adaptacja za pomocą funkcji strzałek :

myArray = myArray.filter( ( el ) => !toRemove.includes( el ) );
Sirko
źródło
23
OP: Jeśli używasz Underscore.js, to w .difference()zasadzie to robi.
Bill Criswell
Właśnie tego szukałem. Dziękuję Ci. @BillCriswell, sprawdzę podkreślenie.
Dotknij
1
@AlecRust Konwertuj wszystkie elementy toRemove()na wielkie i zmieniaj wywołanie zwrotne z elna el.toUpperCase().
Sirko,
5
lub krótszy:myArray = myArray.filter( el => !toRemove.includes( el ) );
538ROMEO
1
czy to nie jest kolejność n ^ 2?
Frazer Kirkman
34

filterMetoda powinna załatwić sprawę:

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

Jeśli toRemovetablica jest duża, tego rodzaju wzorzec wyszukiwania może być nieefektywny. Bardziej wydajne byłoby stworzenie mapy, aby wyszukiwania były O(1)raczej niż 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]);
Ashwin Balamohan
źródło
24

Jeśli korzystasz z tablicy obiektów. Następnie poniższy kod powinien wykonać magię, w której właściwość obiektu będzie kryterium usuwania zduplikowanych elementów.

W poniższym przykładzie duplikaty zostały usunięte, porównując nazwy każdego elementu.

Wypróbuj ten przykład. 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));

Deepak Acharya
źródło
11

Zestawy ECMAScript 6 mogą być używane do obliczania różnych elementów dwóch tablic:

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"]

Benny Neugebauer
źródło
8

Właśnie zaimplementowałem jako:

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

Użyj jako:

myArray.exclude(toRemove);
użytkownik2582833
źródło
1
Nie jest dobrą praktyką rozszerzanie prototypesrodzimych obiektów, takich jak Array. To może mieć długoterminowy konflikt z przyszłym rozwojem języka ( patrz flattenprzypadek )
MarcoL
6

Jeśli nie możesz użyć nowych rzeczy ES5, filtermyślę, że utknąłeś z dwiema pętlami:

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);
    }
  }
}
MarcoL
źródło
filtr nie jest „nowym materiałem HTML5”
goofballLogic
Powinienem był napisać „rzeczy ES5”. Nie był dostępny z ES3
ES3
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) ))
mojtaba roohi
źródło
Czy mógłbyś dodać wyjaśnienie tak dobrze przyjętego pytania?
harmonijka ustna
1
Szukałem godzin dla rozwiązania problemu i właśnie znalazłem, po prostu niesamowite. Dziękuję Ci bardzo!
Tarvo Mäesepp
5

Teraz w smaku jednowarstwowym:

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

Może nie działać na starych przeglądarkach.

Matas Vaitkevicius
źródło
3

Możesz użyć _.differenceBy z 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');

Przykładowy kod tutaj: CodePen

Craciun Ciprian
źródło
Co jeśli atrybut jest zagnieżdżony w obiekcie? Coś testowego jak w twoim przypadku {name: 'deepak', place: 'bangalore', nested: {test: 1}}
Charith Jayasanka
2

A może najprostszy z możliwych:

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)

Eggon
źródło
2
Pamiętaj, że includesnie jest dostępny przed ES7.
Greg,
0

Właściwym sposobem usunięcia wszystkich elementów zawartych w innej tablicy jest uczynienie tablicy źródłowej tym samym obiektem poprzez usunięcie tylko elementów:

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

Lub odpowiednik CoffeeScript:

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

Testowanie narzędzi chrome dev:

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 prawda

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

Korzystanie z frameworka Angular jest najlepszym sposobem na utrzymanie wskaźnika do obiektu źródłowego podczas aktualizacji kolekcji bez dużej liczby obserwatorów i przeładowań.

Михаил Юдин
źródło
Ta odpowiedź jest zła, ponieważ unieważnia najlepsze praktyki. W szczególności nigdy nie modyfikuj obiektów, których nie jesteś właścicielem. W tym przypadku modyfikujesz obiekt Array, co jest dużym nie-nie.
Hybrid web dev
0

Buduję logikę bez żadnych wbudowanych metod, daj mi znać o wszelkich optymalizacjach lub modyfikacjach. Testowałem w edytorze JS, czy działa dobrze.

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;
        }
Shravan R.
źródło