删除另一个数组中包含的所有元素


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()inArray(),效果很好:

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

有没有一种纯Javascript方式无需循环和拼接的方法?




1
您是否可以在javascript或jquery中从另一个数组中删除一个数组的可能重复项-编写问题时,您可能并没有
过多地

无论如何,它将始终涉及某个级别的循环。
蓝天

如果您真的希望它“高效”,则不会使用像这样的函数类型方法.filter()。相反,您将使用for循环。您可以避免.splice()不需要维护原始订单的情况。或者,.splice()如果您认为有很多要删除的项目,有多种方法可以提高效率。
蓝天

Answers:


378

使用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

正是我想要的。谢谢。@BillCriswell,我将检查下划线。
点击

1
@AlecRust将的所有元素转换toRemove()为大写,并将回调从更改elel.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集可用于计算两个数组的不同元素:

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

6

如果您不能使用新的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);
    }
  }
}

过滤器不是“新的HTML5内容”
goofballLogic '16

我应该写“ 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) ))

您介意为这个受欢迎的问题添加一些解释吗?
口琴

1
我花了几个小时寻找问题的解决方案,然后发现它,真是太棒了。非常感谢你!
TarvoMäesepp'19


3

您可以使用_.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


如果属性嵌套在对象内部怎么办?某种测试,例如您的情况{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
请记住,这includes在ES7之前不可用。
格雷格

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是

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

使用Angular框架是在更新集合时保持指针指向源对象的最佳方法,而无需大量观察者和重新加载。


这个答案很糟糕,因为它会使最佳做法无效。具体来说,切勿修改您不拥有的对象。在这种情况下,您要修改Array对象,这是很大的禁止。
混合式网络开发人员,

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;
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.