Delete multiple objects in an array by id - javascript

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

Related

How to get unique combination in array of objects in javascript? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
I have array of objects like this,
let data = [
{ id: 1, name: 'a' },
{ id: 1, name: 'b'},
{ id: 1, name: 'a'},
{ id: 2, name: 'a'},
{ id: 2, name: 'b'},
{ id: 3, name: 'c'},
{ id: 3, name: 'c'}
]
I am trying to achieve unique combination of id and name, so expected output should be like,
output
[
{ id: 1, name: 'a'},
{ id: 1, name: 'b'},
{ id: 2, name: 'a'},
{ id: 2, name: 'b'},
{ id: 3, name: 'c'}
]
I have tried Set method but could not do it for key, value pair.
Please could someone help.
Thanks
Edit- 1
Most solutions have array of string, number or object with one key-value pair. I have two key-value pairs in object.
You can actually use Set for it, you just have to use combination of values that identifies if it is unique.
let data = [
{ id: 1, name: 'a' },
{ id: 1, name: 'b'},
{ id: 1, name: 'a'},
{ id: 2, name: 'a'},
{ id: 2, name: 'b'},
{ id: 3, name: 'c'},
{ id: 3, name: 'c'}
]
const nodup = new Set();
data.forEach(item => nodup.add(`${item.id}-${item.name}`));
console.log(Array.from(nodup))
let uniqueData = Array.from(nodup).map(item => {
const data = item.split('-')
return {id: data[0], name: data[1]};
});
console.log(uniqueData);
After this script, if you want to have array with objects with id and name again, you can simply create it from the result.
let data = [
{ id: 1, name: 'a' },
{ id: 1, name: 'b'},
{ id: 1, name: 'a'},
{ id: 2, name: 'a'},
{ id: 2, name: 'b'},
{ id: 3, name: 'c'},
{ id: 3, name: 'c'}
]
const unique_combos= (arr1) => {
const returned_array = []
arr1.map(element => {
if (!(returned_array.find(e=>e?.id === element?.id && e?.name === element.name)))
returned_array.push(element);
})
return (returned_array);
}
console.log(unique_combos(data))
I know it is not the best way to merge arrays but if that's the only case you want to handle. the above function will handle it for you.
If you want a new array of objects (rather than mutating/deleting objects from the array) you can dedupe the array in one iteration with reduce, and a Set (or an array, whatever takes your fancy).
const data=[{id:1,name:"a"},{id:1,name:"b"},{id:1,name:"a"},{id:2,name:"a"},{id:2,name:"b"},{id:3,name:"c"},{id:3,name:"c"}];
// Create a set to hold the keys
const keys = new Set();
// `reduce` over the data array, initialising the
// accumulator to an empty array.
const out = data.reduce((acc, obj) => {
// Destructure the id and name from each object
const { id, name } = obj;
// Create a key
const key = `${id}-${name}`;
// If the key exists in the set return the
// accumulator immediately
if (keys.has(key)) return acc;
// Otherwise add the key to the set,
// add the object to the accumulator, and
// return it for the next iteration
keys.add(key);
return [...acc, obj];
}, []);
console.log(out);
Additional documentation
Destructuring assignment
Template/string literals
If you want to remove objects from the array (mutation) you can use the same principle but just splice the objects from the array instead.
const data=[{id:1,name:"a"},{id:1,name:"b"},{id:1,name:"a"},{id:2,name:"a"},{id:2,name:"b"},{id:3,name:"c"},{id:3,name:"c"}];
const keys = new Set();
for (let i = 0; i < data.length; ++i) {
const { id, name } = data[i];
const key = `${id}-${name}`;
if (keys.has(key)) data.splice(i, 1);
keys.add(key);
}
console.log(data);
Here's a much cleaner solution for ES6 that I see isn't included here. It uses the Set and the spread operator: ...
var a = [1, 1, 2];
[... new Set(a)]
Which returns [1, 2]

Compare and update two arrays without losing mutated data

I have an array of objects contains data of persons
const oldArr = [
{
id: 1,
name: 'Alex',
},
{
id: 2,
name: 'John',
},
{
id: 3,
name: 'Jack',
}
]
then I add data to this array to each element where I end up with new key called money with value of 20 as the following
oldArr.map((el, index) => el.money = 20)
and the array becomes like this
...
{
id: 2,
name: 'John',
money: 20
},
...
Now, I have a new array with new data (new person) but missing the money I have added before. (careful person with id 2 is not there)
const newArr = [
{
id: 1,
name: 'Alex',
},
{
id: 3,
name: 'Jack',
},
{
id: 4,
name: 'Chris',
},
]
I want to update the old array with new data but also keep the mutated data, and I want the result to end up like this:
const result = [
{
id: 1,
name: 'Alex',
money: 20
},
{
id: 3,
name: 'Jack',
money: 20
},
{
id: 4,
name: 'Chris',
},
]
Thanks for the help.
Just a note: map creates a whole new array, it doesn't make sense to use it for just mutating the contents. Use forEach or just a regular for loop instead.
oldArr.forEach((el) => (el.money = 20));
The following will give you the intended result:
const result = newArr.map(
(newEl) => oldArr.find((el) => el.id === newEl.id) || newEl
);
The OR operator || returns the second argument if the first is falsey.
You can optimize this by mapping items by id instead of brute force searching the old array.
const idMap = new Map();
oldArr.forEach((el) => {
el.money = 20;
idMap.set(el.id, el);
});
const result = newArr.map((newEl) => idMap.get(newEl.id) || newEl);
Stackblitz: https://stackblitz.com/edit/js-f3sw8w?file=index.js
If I getted it clear you are just trying to iterate throw the items of array generating a new array with the property "money" added to each one.
If so the map is the best option, just assign it to a new variable and change the item before return the element like bellow.
const oldArr = [
{
id: 1,
name: "Alex"
},
{
id: 2,
name: "John"
},
{
id: 3,
name: "Jack"
}
];
const newArr = oldArr.map((el) => {
el.money = "20";
return el;
});
console.log(oldArr);
console.log(newArr);
In this way you'll be able to keep both arrays.
If wasn't this, pls let me know.
Just merge the objects:
const result = oldArr.map((person) => ({
...person,
...newArr.find((cur) => cur.id === person.id),
}));

How to find names by id

How to find names by id's ? I have two arrays and want to find names by their id's.
person: [
{id: 1, name: 'abc'},
{id: 2, name: 'xyz'},
{id: 3, name: 'pqr'},
]
data: [
{id: 1, personId: [1,2,3]},
{id: 2, personId: [1,3]},
{id: 3, personId: [1,2]},
]
Expected Output :
personId: [1,2,3] return // abc,xyz,pqr
personId: [1,3] return // abc,pqr
personId: [1,2] return // abc,xyz
I am using react-native. I have tried this :
for (let person of this.state.data) {
for (let personName of person['personId']){
let name = this.state.person.find(nme => nme['id'] === personName);
alert(name);
}
}
Any help would be greatly appreciated
You can use find
result = []
for (let i=0; i < personId.length; i++) {
result.push(person.find(data => data.id === personId[i]).name);
}
in order to be able to retrieve objects in your person array based on the id.
I guess that's JSON data stringify-ied or a JSON in general. So, you can first parse it to JS object to make it easier for you to use JS. But let me leave that part to you. I changed your data to array so that I can directly show you what I would do if it helps.
It's good to use methods that don't mutate original data. So I used array methods slice, forEach and map in this case. This way you can safely create a new data that is a replica of data (var data) but by including new property 'personNames', which is mapped from the other variable (person).
const person = [
{id: 1, name: 'abc'},
{id: 2, name: 'xyz'},
{id: 3, name: 'pqr'},
];
const data = [
{id: 1, personId: [1,2,3]},
{id: 2, personId: [1,3]},
{id: 3, personId: [1,2]},
];
// not to mutate your original data, just in case
const dataWithNames = data.slice();
// console.log(dataWithNames);
// modifying new data to include personNames property
dataWithNames.forEach( eachData => {
// let eachIdP = eachData.personId;
// creating new array by mapping person id to names from person data
let mappedNames = eachData.personId.map( pID => {
// goes to refer person data with same id
person.forEach( eachPerson => {
if ( eachPerson.id === pID ) {
pID = eachPerson.name;
}
} );
return pID;
} );
// console.log(mappedNames);
// adding new property 'personNames' and
// assign them to respective mappedNames
eachData.personNames = mappedNames;
} );
// console.log(dataWithNames);
This will get you the following.
/*
[
{
id: 1,
personId: [ 1, 2, 3 ],
personNames: [ 'abc', 'xyz', 'pqr' ]
},
{ id: 2, personId: [ 1, 3 ], personNames: [ 'abc', 'pqr' ] },
{ id: 3, personId: [ 1, 2 ], personNames: [ 'abc', 'xyz' ] }
]*/
I hope this will help you.

add an object to an array if it doesn't have the same key with one of the objects in the array

I'm using Lodash. I have the array below:
const array = [{id:1,name:a},{id:2,name:b},{id:3,name:c},{id:4,name:d},{id:5,name:e}];
and I'm about to add another object to this array but before that, I need to check if the new object's name is already in the array or not and if there is one with the name I won't add the new object anymore.
I know some ways to do it, for instance, a loop with _.map, but want to make sure if there is an easier way.
You could use Lodash's some which if provided with an appropriate predicate e.g. (item => item.name === newName) will return a boolean indicating whether or not the item already exists (in this case, true would mean the name already exists). The benefit of using this over other iterating methods is that it will stop as soon as it finds one that returns true resulting in better performance.
With native javascript , you can use findIndex, this will return the index of the object where the name matches. If it returns -1 then there is no such object with same name. In that case update the array.
const array = [{
id: 1,
name: 'a'
}, {
id: 2,
name: 'b'
}, {
id: 3,
name: 'c'
}, {
id: 4,
name: 'd'
}, {
id: 5,
name: 'e'
}];
let newObjToAdd = {
id: 1,
name: 'z'
};
let newObjNotToAdd = {
id: 1,
name: 'a'
}
function updateArray(obj) {
let k = array.findIndex((item) => {
return item.name === obj.name;
})
if (k === -1) {
array.push(obj)
} else {
console.log('Array contains object with this name')
}
}
updateArray(newObjToAdd);
console.log(array)
updateArray(newObjNotToAdd);
You don't need lodash for some. You get that with native JS too (ES6):
const array = [{id:1,name:'a'},{id:2,name:'b'},{id:3,name:'c'},{id:4,name:'d'},{id:5,name:'e'}];
console.log(array.some(e => e.name === 'a'));
if (!array.some(e => e.name === 'z')) {
array.push({id: 5, name: 'z'});
}
console.log(array);
Doing this with lodash is few chars shorter but here is how you could do it with ES6 and Array.some:
const array = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }, { id: 4, name: "D" }, { id: 5, name: "C" }];
const maybeUpdate = (arr, obj) => {
if(!array.some(x => x.id == obj.id))
array.push(obj)
}
maybeUpdate(array, {id: 2, name: "F"}) // id exists wont insert
maybeUpdate(array, {id: 12, name: "F"}) // will insert
console.log(array)
Same idea with lodash and _.some would be:
const array = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }, { id: 4, name: "D" }, { id: 5, name: "C" }];
const maybeUpdate = (arr, obj) => {
if(!_.some(array, {id: obj.id}))
array.push(obj)
}
maybeUpdate(array, {id: 2, name: "F"}) // id exists wont insert
maybeUpdate(array, {id: 12, name: "F"}) // will insert
console.log(array)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
Note that you could also use various other ways to get the same result. Array.find or _.find would work as well since all you have to do is to check if there was a hit:
const maybeUpdate = (arr, obj) => {
if(!_.find(array, {id: obj.id})) // or if(!array.find(x => x.id == obj.id))
array.push(obj)
}

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

Categories

Resources