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

我正在寻找一种有效的方法,从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的方法来做到这一点没有循环和剪接?

340126 次浏览

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

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

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

如果您正在使用对象数组。然后,下面的代码将发挥神奇的作用,其中对象属性将作为删除重复项的标准。

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

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

Lodash也有一个效用函数: https://lodash.com/docs#difference < / p >

我只是实现为:

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

使用:

myArray.exclude(toRemove);

现在是一行代码:

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

Might not work on old browsers.

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

你可以从lodash中使用_.differenceBy

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

删除另一个数组中包含的所有元素的正确方法是通过只删除元素来使源数组成为相同的对象:

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开发工具内测试:

< p > 19:33:04.447 = 1 < br > 19:33:06.354 b = 2 < br > 19:33:07.615 c = 3 < br > 19:33:09.981 arr = [a,b,c]
19:33:16.460 arr1 = arr

19:33:20.317 arr1 === arr
19:33:20.331真正< br > < / p > < p > 19:33:43.592 arr.removeContained ([c]) < br > 19:33:52.433 Arr === arr1 < br > 19:33:52.438 真正的 < br > < / p >

使用Angular框架是在更新集合时保持指针指向源对象的最佳方法,而不需要大量的监视器和重载。

我没有使用任何内置方法构建逻辑,请让我知道任何优化或修改。 我在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;
}
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) ))

最简单的方法如何:

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)

如果你正在使用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])
);
}

这已经很晚了,但是添加这个来解释@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)

//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' ]

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

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