I'm trying to find and replace the array if an incoming arrays matches the existing one but unfortunately, I'm stucked with the some
Here's my existing array.
let existingData = [{
id: 1,
product: 'Soap',
price: '$2'
},{
id: 2,
product: 'Sofa',
price: '$30'
},{
id: 3,
product: 'Chair',
price: '$45'
}]
And here's my incoming array.
const updateData = [{
id: 1,
product: 'Soap',
price: '$3'
},{
id: 2,
product: 'Sofa',
price: '$35'
}]
So far, I saw the foreach but unfortunately, I'm not sure how can I use it if the term is an array. But I get stuck and I can't proceed.
const updateData = [{
id: 1,
product: 'Soap',
price: '$3'
},{
id: 2,
product: 'Sofa',
price: '$35'
}]
existingData.forEach(d=>{
if(d.id === ??? how can I match this to the incoming array?)
// if matches, then update the existing data with the updated one.
})
And the expected result must be something like this:
let existingData = [{
id: 1,
product: 'Soap',
price: '$3'
},{
id: 2,
product: 'Sofa',
price: '$35'
},{
id: 3,
product: 'Chair',
price: '$45'
}]
If in some cases, the data is not present in the existingData, then the incoming array will just add simply in the existing array.
Please help how can I achieve it and if there's a better and cleaner way to do this, please let me know. Thank you!
You can easily achieve this result using forEach and find
let existingData = [{
id: 1,
product: "Soap",
price: "$2",
},
{
id: 2,
product: "Sofa",
price: "$30",
},
{
id: 3,
product: "Chair",
price: "$45",
},
];
const updateData = [{
id: 1,
product: "Soap",
price: "$3",
},
{
id: 2,
product: "Sofa",
price: "$35",
},
];
updateData.forEach((obj) => {
let isExist = existingData.find((o) => o.id === obj.id);
if (isExist) {
isExist.price = obj.price;
isExist.product = obj.product;
}
});
console.log(existingData);
If there are multiple properties that need to be updated then you can use for..in loop over the updated object and replace the prop in the existing property.
updateData.forEach((obj) => {
let isExist = existingData.find((o) => o.id === obj.id);
if (isExist) {
for (let prop in obj) {
isExist[prop] = obj[prop];
}
}
});
If you want to add the data if it doesn't exist in the existing array then you need to push it into existingData array.
let existingData = [{
id: 1,
product: "Soap",
price: "$2",
},
{
id: 2,
product: "Sofa",
price: "$30",
},
{
id: 3,
product: "Chair",
price: "$45",
},
];
const updateData = [{
id: 1,
product: "Soap",
price: "$3",
},
{
id: 2,
product: "Sofa",
price: "$35",
},
{
id: 6,
product: "Sofa",
price: "$135",
},
];
updateData.forEach((obj) => {
let isExist = existingData.find((o) => o.id === obj.id);
if (isExist) {
for (let prop in obj) {
isExist[prop] = obj[prop];
}
} else {
existingData.push(obj);
}
});
console.log(existingData);
existingData.forEach(existingItem => {
let item = updatedDate.find(u => u.id === existingItem.id);
if(item){
existingItem.product = item.product;
existingItem.price= item.price;
}
});
Given your existingData and updateData, you can quite simply do something like this:
// form a temporary object mapping updated objects' ids to the new ids
const updateDataByKeys = Object.fromEntries(updateData.map(e => [e.id, e]));
// map through `existingData`, replacing old entries with updated where they
// exist in the above temporary object, using the old object if they don't.
const newData = existingData.map(e => updateDataByKeys[e.id] || e);
Creating the temporary object should make this approach quite a bit faster than approaches using .find() on updateData.
If you need to merge the data from updateData into the existing objects, you could do
const newData = existingData.map(
e => updateDataByKeys[e.id] ? ({...e, ...updateDataByKeys[e.id]}) : e
);
EDIT: Based on comments, if you also need to add new objects from updateData:
// form a temporary object mapping updated objects' ids to the new ids
const updateDataByKeys = Object.fromEntries(updateData.map(e => [e.id, e]));
// Map through `existingData`, replacing old entries with updated where they
// exist in the above temporary object, using the old object if they don't.
// When using an update object, removes it from the mapping; the left-over
// new data (which had no ID in the old data) are then concatenated to the
// list.
const newData = existingData.map(e => {
if(updateDataByKeys[e.id]) {
const val = updateDataByKeys[e.id];
delete updateDataByKeys[e.id];
return val;
}
return e;
}).concat(Object.values(updateDataByKeys));
Related
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),
}));
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
I am trying to find duplicate objects in a list of objects and add new parameters to the duplicate one.
Below snipped code is what I implemented so far. The problem is that it adds desired parameters to every object in the list.
const list = [{
id: 1,
name: 'test1'
},
{
id: 2,
name: 'test2'
},
{
id: 3,
name: 'test3'
},
{
id: 2,
name: 'test2'
}
];
const newList = list.reduce(
(unique, item) => (unique.includes(item) ? unique : [...unique, {
...item,
duplicated: true,
name: `${item.name}_${item.id}`
}]), []
);
console.log(newList);
Since there are two duplicate objects by id, the duplicated one should have duplicated and new name parameters. What part is wrong in my implementation?
By using findIndex method:
const list = [{
id: 1,
name: 'test1'
},
{
id: 2,
name: 'test2'
},
{
id: 3,
name: 'test3'
},
{
id: 2,
name: 'test2'
}
];
const newList = list.reduce(
(unique, item) => (unique.findIndex(x => x.id === item.id) > -1 ? [...unique, {
...item,
duplicated: true,
name: `${item.name}_${item.id}`
}] : [...unique, item]), []);
console.log(newList);
It can be written simply:
const
list = [
{ id: 1, name: 'test1' },
{ id: 2, name: 'test2' },
{ id: 3, name: 'test3' },
{ id: 2, name: 'test2' }
],
uniqueList = list.reduce((arr, { id, name }) =>
arr.concat({
id,
name,
...arr.some(item => id === item.id) && { duplicate: true, name: `${name}_${id}` }
}), []);
console.log(uniqueList);
The problem was that when you called includes you were actually looking for an object whose pointer exists in the array.
In order to find an object which has property are the same as a requested property, you have no choice but to use functions such as some or every that is different from includes - you can send them a callback and not just an object.
This question already has answers here:
Create array of unique objects by property
(17 answers)
Closed 3 years ago.
I have an object that looks like this:
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
I need an array of the unique user hashes like this:
[
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
I'm able to retrieve all the users attributes from the posts array by doing:
const postUsers = posts.map(post => post.user)
which returns:
[
{ id: 5564, name: 'john'},
{ id: 5564, name: 'john'},
{ id: 5560, name: 'jane'}
]
where user john is listed twice
I've been able to get my desired result by doing:
const unique = {};
const uniqueUsers = [];
for(var i in postUsers){
if(typeof(unique[postUsers[i].id]) == "undefined"){
uniqueUsers.push(postUsers[i]);
}
unique[postUsers[i].id] = 0;
};
uniqueUsers
but there must be a cleaner way.
I've also been able to return the unique ids of all users by doing:
var ids = posts.map(post => post.user.id)
var uniqueIds = Array.from(new Set(ids)).sort();
which returns
[5564, 5560]
not sure if that helps. this article helped me a little https://medium.com/tomincode/removing-array-duplicates-in-es6-551721c7e53f
You could take a Map and get only the unique users.
const
posts = [{ id: 0, user: { id: 5564, name: 'john'} }, { id: 1, user: { id: 5564, name: 'john'} }, { id: 2, user: { id: 5560, name: 'jane'} }],
unique = Array.from(posts.reduce((m, { user }) => m.set(user.id, user), new Map).values());
console.log(unique);
If you don't mind using lodash you can do something like
const users = _map.(posts, 'user') // To get the list of users
_.uniqBy(users, 'id') // to get the uniq ones
Put the objects directly in uniqueUsers, then use Object.values() at the end to convert the object to an array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
];
let uniqueUsers = {};
posts.forEach(({user}) => uniqueUsers[user.id] = user);
uniqueUsers = Object.values(uniqueUsers);
console.log(uniqueUsers);
Use reduce to reduce the array by checking if the value is already in the array. If it is already in the array, return the current state of the array, otherwise add the item to the array.
const posts = [
{ id: 0, user: { id: 5564, name: 'john'} },
{ id: 1, user: { id: 5564, name: 'john'} },
{ id: 2, user: { id: 5560, name: 'jane'} }
]
const r = posts.map(i => i.user).reduce((acc, itm) => {
return !acc.find(i => i.id == itm.id) && acc.concat(itm) || acc
}, [])
console.log(r)
How can i push an array into an exists array?
Cases[caseid].items = itemscase;
thats what i tried.
I have some "Cases"
for(var c in Cases) {
for each Case(s) i want to push different new "items" to an exists array.
The array looks like this:
'123':
[ { id: 123,
skus: [Array],
name: 'xyz',
img: '/public/images/cases/10018.png'}
now i want to push a new array (itemscase) to that like this
'123':
[ { id: 123,
skus: [Array],
name: 'xyz',
img: '/public/images/cases/10018.png'
items: [Array]}
The array itemscase is correct and working and looks like that
[ { sku: 12345,
name:
'testname',
price: 15 }]
but for some reason the last run will push only to the last "Cases".
So if i have 10 "Cases" only the last gets items all before not.
Here some more Code.
for(var c in Cases) {
var caseid = Cases[c][0].id;
for(var i in itemsres) {
var item = itemsres[i];
itemscase.push({
sku: item.sku,
name: item.name
price: item.suggested_price_floor
});
}
Cases[caseid].items = itemscase;
}
itemsres is also fine, creating itemscase works fine and something.
For me looks like something is wrong with the add an array into another array
I think i do something wrong...
Here the maps adds the items to each node using a map.
NOTE: You are not filtering on what items to add where, I suspect you want to add items that match the skus?
Let me know and we can make the right changes.
let Cases = [{
id: 123,
skus: [1, 2, 3],
name: 'xyz',
img: '/public/images/cases/10018.png'
},
{
id: 234,
skus: [4, 5, 6],
name: 'abc',
img: '/public/images/cases/10019.png'
}
];
let itemres = [{
sku: 12345,
name: 'testname',
price: 15
},
{
sku: 45677,
name: 'testname',
suggested_price_floor: 20
}
];
// add items to cases
Cases = Cases.map(c => {
c.items = itemres.map(i => {
return {
sku: i.sku,
name: i.name,
price: i.suggested_price_floor
};
})
return c;
});
console.log(Cases);
Its hard to test without the full code, but based on your examples, I suggest you to try out this snippet:
Object.keys(Cases).forEach(id => {
Cases[id].forEach(caseItem => {
caseItem.items = itemsres.map(x => ({
sku: x.sku,
name: x.name,
price: x.suggested_price_floor,
}));
});
});
Basically, here I'm looping through all cases using Object.keys() when object, and .forEach() when array. The Array.map() function does what your (empty array + loop + push) is trying to do.