345

如果它们存在于另一个数组中,我正在寻找一种有效的方法来从 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 方法可以做到这一点而无需循环和拼接?

4

18 回答 18

545

使用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 ) );
于 2013-11-13T15:16:35.190 回答
53

ECMAScript 6 集可以允许更快地计算一个数组中不在另一个数组中的元素:

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

const difference = myArray.filter( x => !toRemove.has(x) );

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

由于目前浏览器使用的 V8 引擎的查找复杂度为 O(1),因此整个算法的时间复杂度为 O(n)。

于 2017-05-26T14:35:18.763 回答
43
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) ))
于 2019-04-29T09:45:36.787 回答
42

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]);
于 2013-11-13T15:17:34.883 回答
27

如果您使用的是对象数组。然后下面的代码应该会发挥作用,其中对象属性将成为删除重复项的标准。

在下面的示例中,已删除重复项比较每个项目的名称。

试试这个例子。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));

于 2015-07-07T12:18:55.157 回答
14

Lodash has an utility function for this as well: https://lodash.com/docs#difference

于 2015-10-13T09:03:17.500 回答
12

最简单的怎么样:

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)

于 2019-08-07T15:14:09.053 回答
10

我刚刚实现为:

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

用于:

myArray.exclude(toRemove);
于 2016-05-04T09:57:04.763 回答
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);
    }
  }
}
于 2013-11-13T15:18:08.603 回答
5

现在单线风味:

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

可能不适用于旧浏览器。

于 2016-07-18T14:22:56.290 回答
4

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

于 2018-03-08T11:41:37.467 回答
3

这已经很晚了,但添加它以解释@mojtaba roohi已回答的内容。第一个代码块将不起作用,因为每个数组都有不同的对象,即 df[0] != nfl[2]。这两个对象看起来相似但完全不同,当我们使用像数字这样的原始类型时情况并非如此。

let df = [ {'name': 'C' },{'name': 'D' }] 
let nfl = [ {'name': 'A' },{'name': 'B' },{'name': 'C' },{'name': 'D' }] 
let res = nfl.filter(x => df.indexOf(x)<0)
console.log(res)

这是工作代码:

let df = [{'name': 'C' },{'name': 'D' }]
let nfl = [ {'name': 'A' },{'name': 'B' },{'name': 'C' },{'name': 'D' }];
let res = nfl.filter((o1) => !df.some((o2) => o1.name === o2.name));
console.log(res)

于 2021-06-27T13:13:44.940 回答
1

如果您使用的是 Typescript 并且想要匹配单个属性值,这应该基于Craciun Ciprian 的上述回答。

您还可以通过允许非对象匹配和/或多属性值匹配来使其更通用。

/**
 *
 * @param arr1 The initial array
 * @param arr2 The array to remove
 * @param propertyName the key of the object to match on
 */
function differenceByPropVal<T>(arr1: T[], arr2: T[], propertyName: string): T[] {
  return arr1.filter(
    (a: T): boolean =>
      !arr2.find((b: T): boolean => b[propertyName] === a[propertyName])
  );
}
于 2020-09-04T16:47:33.037 回答
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 框架是保持指向源对象的指针的最佳方式。

于 2018-07-02T12:45:06.070 回答
0
const first = [
  { key: "Value #1", key1: "Value #11" },
  { key: "Value #2", key1: "Value #12" },
  { key: "Value #3", key1: "Value #13" },
];

const second = [{ key: "Value #1", key1: "Value #11" }];

const toRemove = second.map((x) => Object.values(x).join("."));

const remainingData = first.filter( (x) => !toRemove.includes(Object.values(x).join(".")) );

console.log(JSON.stringify(remainingData, null, 2));
于 2022-02-26T08:46:37.907 回答
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;
        }
于 2018-07-28T22:12:19.023 回答
0

高性能和不可变的解决方案

Javascript

const excludeFromArr = (arr, exclude) => {
  const excludeMap = exclude.reduce((all, item) => ({ ...all, [item]: true }), {});
  return arr.filter((item) => !excludeMap?.[item]);
};

打字稿:

const excludeFromArr = (arr: string[], exclude: string[]): string[] => {
  const excludeMap = exclude.reduce<Record<string, boolean>>((all, item) => ({ ...all, [item]: true }), {});
  return arr.filter((item) => !excludeMap?.[item]);
};
于 2022-02-24T15:52:20.187 回答
0

//Using the new ES6 Syntax

    console.log(["a", "b", "c", "d", "e", "f", "g"].filter(el => !["b", "c", "g"].includes(el)));

    // OR

    // Main array
    let myArray = ["a", "b", "c", "d", "e", "f", "g"];

    // Array to remove
    const toRemove = ["b", "c", "g"];

    const diff = () => (myArray = myArray.filter((el) => !toRemove.includes(el)));
  console.log(diff()); // [ 'a', 'd', 'e', 'f' ]

    // OR

    const diff2 = () => {
      return myArray = myArray.filter((el) => !toRemove.includes(el));
    };
    console.log(diff2()); // [ 'a', 'd', 'e', 'f' ]

于 2022-02-18T19:48:08.927 回答