Javascript arrays: удалить все элементы, содержащиеся в другом массиве

Я ищу эффективный способ удалить все элементы из массива 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() и inArray(), который хорошо работает:

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

Есть ли чистый javascript способ сделать это без цикла и сплайсинга?

Ответ 1

Используйте метод 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 ) );

Ответ 2

Метод 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]);

Ответ 3

Если вы используете массив объектов. Затем нижеприведенный код должен делать магию, где свойство объекта будет критерием для удаления повторяющихся элементов.

В приведенном ниже примере дубликаты удалены, сравнивая имя каждого элемента.

Попробуйте этот пример. 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));

Ответ 5

Наборы ECMAScript 6 могут использоваться для вычисления различных элементов двух массивов:

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

Ответ 6

Я только что реализовал как:

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

Использовать как:

myArray.exclude(toRemove);

Ответ 7

Если вы не можете использовать новый материал ES5, такой filter, я думаю, вы застряли с двумя циклами:

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

Ответ 8

Теперь в однострочном вкусе:

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

Ответ 9

Вы можете использовать _.differenceBy из 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');

Пример кода здесь: CodePen

Ответ 10

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

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

Ответ 11

Как насчет простейшего из возможных:

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)

Ответ 12

Правильный способ удалить все элементы, содержащиеся в другом массиве, состоит в том, чтобы сделать исходный массив тем же объектом, удалив только элементы:

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 Dev Tools:

19: 33: 04.447 а = 1
19: 33: 06.354 b = 2
19: 33: 07.615 с = 3
19: 33: 09.981 обр = [а, б, в]
19: 33: 16.460 обр1 = обр

19: 33: 20.317 обр1 === обр
19: 33: 20,331 верно

19: 33: 43.592 arr.removeContained([a, c])
19: 33: 52.433 обр === обр1
19: 33: 52,438 верно

Использование Angular Framework - лучший способ сохранить указатель на исходный объект при обновлении коллекций без большого количества наблюдателей и перезагрузок.

Ответ 13

Я строю логику без использования каких-либо встроенных методов, пожалуйста, дайте мне знать об оптимизации или модификациях. Я тестировал в редакторе 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;
        }