How to remove object from array by property value? [duplicate] - javascript

This question already has answers here:
Compare the elements of two arrays by Id and remove the elements from the one array that are not presented in the other
(3 answers)
Closed 6 years ago.
I have this javascript objects:
var arr1 = [{id:'124',name:'qqq'},
{id:'589',name:'www'},
{id:'45',name:'eee'},
{id:'567',name:'rrr'}]
var arr2 = [{id:'124',name:'ttt'},
{id:'45',name:'yyy'}
From arr1 I need remove all objects with the same id in arr2.
Here is the desired result of arr1:
var arr1 = [{id:'589',name:'www'},
{id:'567',name:'rrr'}]
What is elegant way to implement it in Javascript?

Here is a way to pick up the ID values on the fly. It binds the intermediate object to this via the optional thisArg argument of filter:
var arr1 = [{id:'124',name:'qqq'},
{id:'589',name:'www'},
{id:'45',name:'eee'},
{id:'567',name:'rrr'}];
var arr2 = [{id:'124',name:'ttt'},
{id:'45',name:'yyy'}];
arr1 = arr1.filter(function (el) {
return !this[el.id];
}, arr2.reduce(function (obj, el) {
return obj[el.id] = 1, obj;
}, {}));
console.log(arr1);
The intermediate object that is passed as the last argument to filter looks like this:
{ 45: 1, 124: 1 }
This makes it straightforward to check if an element of arr1 needs to be rejected or not.

I would get a condensed list of all IDs in arr2, then use indexOf or find from within a filter to exclude those from the revised arr1:
var arr1 = [{
id: '124',
name: 'qqq'
}, {
id: '589',
name: 'www'
}, {
id: '45',
name: 'eee'
}, {
id: '567',
name: 'rrr'
}];
var arr2 = [{
id: '124',
name: 'ttt'
}, {
id: '45',
name: 'yyy'
}];
var ids = arr2.map(function(it) {
return it.id;
});
var unique = arr1.filter(function(it) {
return ids.indexOf(it.id) === -1; // does not contain
});
console.log(unique);
If you don't want to map out the IDs -- although I would recommend doing so, since it means you don't have to walk through arr2 repeatedly -- you can use something like:
var unique = arr1.filter(function(it) {
return !arr2.some(function (other) {
return it.id === other.id;
});
});

I suggest to use a hash table for this.
var arr1 = [{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '45', name: 'eee' }, { id: '567', name: 'rrr' }],
arr2 = [{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }];
arr1 = arr1.filter(function (a) {
return !this[a.id];
}, function (hash) {
arr2.forEach(function (a) { hash[a.id] = true; });
return hash;
}(Object.create(null)));
console.log(arr1);
ES6
var arr1 = [{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '45', name: 'eee' }, { id: '567', name: 'rrr' }],
arr2 = [{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }];
arr1 = arr1.filter((hash =>
(arr2.forEach(a => hash[a.id] = true), a => !hash[a.id]))(Object.create(null)));
console.log(arr1);

I would highly encourage using underscorejs for this kind of object manipulation. From the documentation:
var evens = _.filter([1, 2, 3, 4, 5, 6], function(num){ return num % 2 == 0; });
=> [2, 4, 6]
if you want to do the same thing on an object:
_.filter({"a":1,"b":2,"c":3,"d":4}, function(value,key){ return value % 2 == 0; })
In your specific case this would be the solution:
var newArray = _.filter(arr1,(object1) => {
return !_.contains(_.pluck(arr2,'id'),object1.id);
});
This is a chart showing improvements of Underscore and Lodash on native methods:
specifically on filter it shows more than a 20% improvement.
Taken from this article.

Related

Delete multiple objects in an array by id

I have a main array of objects with each object having some key/values as well as a "id" key with 1,2,3,4,5, etc
Now I have another array representing just id's (like [2,3])
I want to use this array to delete objects from the main array...so in this case, objects from the main array having id's 2 & 3 should be deleted
While I am aware of findBy(id), I am not sure if that can be used to delete multiple objects at once.
You can use filter. In the filter callback function check if the id is also there in id array by using includes
let idArr = [1, 2]
let obj = [{
id: 1,
name: 'abc'
},
{
id: 2,
name: 'abc'
},
{
id: 3,
name: 'abc'
},
{
id: 4,
name: 'abc'
}
];
let data = obj.filter(item => !idArr.includes(item.id));
console.log(data);
console.log(obj)
using filter might work well here. you could write something like:
var newArray = oldArray.filter(object => !ids.includes(object.id))
You can do it, like this:
[2,3].forEach(key => {
delete object[key];
})
You can use filter method for this.
Ex:
let id = 2;
let list = [{
Id: 1,
Name: 'a'
}, {
Id: 2,
Name: 'b'
}, {
Id: 3,
Name: 'c'
}];
let lists = list.filter(x => {
return x.Id != id;
})
console.log(lists);
Assuming you want to delete items from the original array by entirely removing the element from the array (and you don't want to get a new array), you can take advantage of
Array.splice
let idArr = [1, 2];
let obj = [{
id: 1
},
{
id: 2
},
{
id: 3
},
{
id: 4
}
];
for (let id of idArr) {
// look for the element by its id.
const objIdRef = obj.find(i => i.id === id);
// if it actually exists, splice it.
objIdRef && obj.splice(obj.indexOf(objIdRef), 1);
}
console.log(obj);
If the obj array is big, you might want to make a map from it before processing the id array, so that the complexing is reduced to O(1) when the delete process begins.
Perhaps This is what you want:
var arr= [{id:1, name: "foo"}, {id:2, name: "bar"}, {id:3, name:"not to be deleted"}];
var idsToDelete = [1, 2];
var res = arr.map((i, idx)=>{
return arr[idx] = idsToDelete.includes(i.id)? undefined : arr[idx]
}).filter(i=>i)
console.log(res)
You can try Lodash.js functions _.forEach() and _.remove()
let valuesArr = [
{id: 1, name: "dog"},
{id: 2, name: "cat"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
{id: 5, name: "pig"},
];
let removeValFromIndex = [
{id: 2, name: "cat"},
{id: 5, name: "pig"},
];
_.forEach(removeValFromIndex, (indi) => {
_.remove(valuesArr, (item) => {
return item.id === indi.id;
});
})
console.log(valuesArr)
/*[
{id: 1, name: "dog"},
{id: 3, name: "rat"},
{id: 4, name: "bat"},
]; */
Don't forget to clone (_.clone(valuesArr) or [...valuesArr]) before mutate your array

Filter array of objects by another array with duplicate keys

I have this array of objects:
const data = [
{
id: 1,
name: 'Name1',
encryptionKey: 'AAA'
},
{
id: 2,
name: 'Name2',
encryptionKey: 'BBB'
},
{
id: 3,
name: 'Name3',
encryptionKey: 'CCC'
}
]
and another array of encryption keys:
const encryptionKeys = ['AAA', 'BBB']
I am then filtering the data array based on the encryptionKeys array like this:
var filtered = data.filter(function(item) {
return encryptionKeys.indexOf(item.encryptionKey) !== -1;
});
which works and filters the objects and saves them in a new array. The problem is however if the encryptionKey array has duplicated keys, for example:
const encryptionKeys = ['AAA', 'BBB', 'BBB']
then all duplicate keys will be ignored and the filtered array will only have, in this case, 2 objects instead of 3. What am I doing wrong in my filtering code? The filtered array should have duplicate objects if the encryptionKeys array has duplicate values.
Make note of .flat() 's Browser compatibility and then see #babel/polyfill
const data = [
{
id: 1,
name: 'Name1',
encryptionKey: 'AAA'
},
{
id: 2,
name: 'Name2',
encryptionKey: 'BBB'
},
{
id: 3,
name: 'Name3',
encryptionKey: 'CCC'
}
]
const keys = ['AAA', 'BBB', 'BBB', 'AAA', 'BBB', 'ZZZ']
const occurances = data.map(d => {
const { encryptionKey } = d
const keyedOccurances = keys
.filter(k => k === encryptionKey)
.map(k => encryptionKey === k && d)
return keyedOccurances.length && keyedOccurances
})
.filter(Boolean)
.flat()
console.log(occurances)
Easy - just use filter on encryptionKeys beforehand:
var filtered = data.filter(function(item) {
return encryptionKeys.filter((e, i, a) => a.indexOf(e) == i).indexOf(item.encryptionKey) !== -1;
});
Alternatively, make an Array from a Set:
var filtered = data.filter(function(item) {
return [...new Set(encryptionKeys)].indexOf(item.encryptionKey) !== -1;
});
Make your encryption keys unique before you compare and filter it.
var encryptionKeys = ['AAA', 'BBB', 'BBB'];
var unique = encryptionKeys.filter((v, i, a) => a.indexOf(v) === i);
console.log(unique);
You could map the wanted items.
const
data = [{ id: 1, name: 'Name1', encryptionKey: 'AAA' }, { id: 2, name: 'Name2', encryptionKey: 'BBB' }, { id: 3, name: 'Name3', encryptionKey: 'CCC' }],
encryptionKeys = ['AAA', 'BBB', 'BBB'],
result = encryptionKeys.map(key => data.find(o => o.encryptionKey === key));
console.log(result);
A short approach with a Map and filtering the keys in advance.
const
data = [{ id: 1, name: 'Name1', encryptionKey: 'AAA' }, { id: 2, name: 'Name2', encryptionKey: 'BBB' }, { id: 3, name: 'Name3', encryptionKey: 'CCC' }],
encryptionKeys = ['AAA', 'BBB', 'BBB', 'DDD'],
map = new Map(data.map(o => [o.encryptionKey, o])),
result = encryptionKeys
.filter(Map.prototype.has, map)
.map(Map.prototype.get, map);
console.log(result);

How to return the duplicate objects of two arrays? [duplicate]

This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 4 years ago.
Let's say we have:
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
var array2 = [{ id: 1 }, { id: 2}]
I know you can concat the two arrays like this (without having duplicates):
Array.from(new Set(array1.concat(array2)))
Now, how to create a new array with only the objects that share the same values?
var array2 = [{ id: 1 }]
You can use .filter() and .some() to extract matching elements:
let array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
let array2 = [{ id: 1 }, { id: 2}]
let result = array1.filter(({id}) => array2.some(o => o.id === id));
console.log(result);
Useful Resources:
Array.prototype.filter()
Array.prototype.some()
You could take a set with the id of the objects and filter array2
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }] ,
array2 = [{ id: 1 }, { id: 2}],
s = new Set(array1.map(({ id }) => id)),
common = array2.filter(({ id }) => s.has(id));
console.log(common);
The requested sameness with identical objects.
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }] ,
array2 = [array1[0], { id: 2}],
s = new Set(array1),
common = array2.filter(o => s.has(o));
console.log(common);
Assuming, by your definition, that the objects, even if they have the same structure, are not really the same object, I define an 'equality function', and then, with filter and some:
var array1 = [{ id: 1 }, { id: 4}, { id: 3 }]
var array2 = [{ id: 1 }, { id: 2}];
var equal = function(o1, o2) { return o1.id === o2.id };
var result = array2.filter(function(item1) {
return array1.some(function(item2) { return equal(item1, item2) });
});
console.log(result);

Lodash check if any object in array contains id match from another array

I have one user array like:
var users = [{
id: 1,
name: 'ABC',
isDisplay: true
}, {
id: 2,
name: 'XYZ',
isDisplay: true
}, {
id: 3,
name: 'JKL',
isDisplay: true
}];
And another array selectedUsers which contains some object from above array like:
var selectedUsers = [{
id: 1,
name: 'ABC'
},
{
id: 3,
name: 'JKL'
}];
Not with lodash, i want to indentify which object are present in second array with matching its ID.
_.each(users, (_u) => {
if(selectedUsers.includes(_u)) {
_u.isDisplay = false;
} else {
_u.isDisplay = true;
}
});
I have tried to match whole object with includes but it dint work, because i am using angularjs, so angular put some $$hashkey with object, so it will not match, Is there any other way to do this.
var users = [{
id: 1,
name: 'ABC',
isDisplay: true
}, {
id: 2,
name: 'XYZ',
isDisplay: true
}, {
id: 3,
name: 'JKL',
isDisplay: true
}];
var selectedUsers = [{
id: 1,
name: 'ABC'
},
{
id: 3,
name: 'JKL'
}];
var intersection = _.intersectionBy(users, selectedUsers, 'id');
console.log(intersection);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.js"></script>
Create a Set of selected ids (selectedUsersIds). Iterate the users array with Array#forEach, assign the value of isDisplay by checking if the id exists in the selectedUsersIds set:
const users = [{"id":1,"name":"ABC","isDisplay":true},{"id":2,"name":"XYZ","isDisplay":true},{"id":3,"name":"JKL","isDisplay":true}];
const selectedUsers = [{"id":1,"name":"ABC"},{"id":3,"name":"JKL"}];
const selectedUsersIds = new Set(selectedUsers.map(({ id }) => id));
users.forEach((u) => u.isDisplay = selectedUsersIds.has(u.id));
console.log(users);

Manipulating objects in array of objects

I have this javascript objects:
var arr1 = [{id:'124',name:'qqq'},
{id:'589',name:'www'},
{id:'45',name:'eee'},
{id:'567',name:'rrr'}]
var arr2 = [{id:'124',name:'ttt'},
{id:'45',name:'yyy'}
I need to replace objects in arr1 with items from arr2 with same id.
Here how I achive the desired result:
arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);
And here is the result:
var arr1 = [{id:'124',name:'ttt'},
{id:'589',name:'em'},
{id:'45',name:'yyy'},
{id:'567',name:'eme'}];
But the problem that this solution:
arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);
Don't work in IE browser.
How can I change the row above to get the desired result in IE and chrome browsers?
var arr1 = [{
id: '124',
name: 'qqq'
}, {
id: '589',
name: 'www'
}, {
id: '45',
name: 'eee'
}, {
id: '567',
name: 'rrr'
}];
var arr2 = [{
id: '124',
name: 'ttt'
}, {
id: '45',
name: 'yyy'
}];
var res = arr1.map(obj => arr2.find(o => o.id === obj.id) || obj);
console.log(res);
If you want to use Array.prototype.find() you would need to use recommended polyfill for browsers that don't support it.
See MDN Array.protoype.find() polyfill
If you don't want to use a polyfill, simply reduce the ids first then map.
var arr1 = [{id:'124',name:'qqq'},
{id:'589',name:'www'},
{id:'45',name:'eee'},
{id:'567',name:'rrr'}]
var arr2 = [{id:'124',name:'ttt'},
{id:'45',name:'yyy'}]
var byIds = arr2.reduce((acc, item) => {
acc[item.id] = item;
return acc;
}, {})
var replacedArr1 = arr1.map(item => byIds[item.id] || item);
You have tagged lodash to this, so why not use lodash functions _ .find and _ .map instead of the native functions with limited browser support.
_.map(arr1, obj => _.find(arr2, o => o.id === obj.id) || obj);
To state the obvious, you also need to transpile the ES6 style arrow functions and what not to support older browsers.
Please, did you think of underscorejs you will find cross browser functions like find, filter and map
int lastIndex = 0
var result = _.map(arr1 , function(num){
if (arr1.id == arr2[lastIndex].id){
return arr2[lastIndex++];
}
return arr1;
});
You could iterate over arr2 and build an object as hash table and then iterate over arr1 for changing the elements.
var arr1 = [{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '45', name: 'eee' }, { id: '567', name: 'rrr' }],
arr2 = [{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }],
hash = Object.create(null);
arr2.forEach(function (a) {
this[a.id] = a;
}, hash);
arr1.forEach(function (a, i, aa) {
if (this[a.id]) {
aa[i] = this[a.id];
}
}, hash);
console.log(arr1);
Or use a version with short circuit.
var arr1 = [{ id: '124', name: 'qqq' }, { id: '589', name: 'www' }, { id: '45', name: 'eee' }, { id: '567', name: 'rrr' }],
arr2 = [{ id: '124', name: 'ttt' }, { id: '45', name: 'yyy' }],
hash = Object.create(null);
hash.count = arr2.length;
arr2.forEach(function (a) {
this[a.id] = a;
}, hash);
arr1.some(function (a, i, aa) {
if (this[a.id]) {
aa[i] = this[a.id];
return !--this.count;
}
}, hash);
console.log(arr1);
What I would do is use a for loop to loop through each item in the 2nd array. Then loop through the first array to see if the ID matches. If it does, set the name to the name from the second array.
var arr1 = [{id:'124',name:'qqq'},
{id:'589',name:'www'},
{id:'45',name:'eee'},
{id:'567',name:'rrr'}];
var arr2 = [{id:'124',name:'ttt'},
{id:'45',name:'yyy'}];
for (var i = 0; i < arr2.length; i++) {
for (var j = 0; j < arr1.length; j++) {
if (arr2[i].id === arr1[j].id) {
arr1[j].name = arr2[i].name;
}
}
}
here is a fiddle https://jsfiddle.net/k0grurx5/

Categories

Resources