Update array of objects with array of objects - javascript

My apologies if this has been addressed before, but I couldn't get it to work with anything I found.
Assume I have 2 arrays - arr1, arr2. I want to update the objects in arr1 if the the property id matches in arr1 and arr2. Objects that exist in arr2 but not in arr1 - meaning the property id does not exist in arr1 - should be pushed to arr1.
Example:
let arr1 = [
{id: 0, name: "John"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
]
let arr2 = [
{id: 0, name: "Mark"},
{id: 4, name: "Sara"}
]
# Expected Outcome
let outcome = [
{id: 0, name: "Mark"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"},
{id: 4, name: "Sara"}
]

You can use reduce and find for this:
const arr1 = [
{id: 0, name: "John"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
];
const arr2 = [
{id: 0, name: "Mark"},
{id: 4, name: "Sara"}
];
arr2.reduce((res, item) => {
const existingItem = res.find(x => x.id === item.id);
if (existingItem) { existingItem.name = item.name; }
else { res.push(item); }
return res;
}, arr1);
console.log(arr1);

You could do this:
let arr1 = [
{id: 0, name: "John"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
]
let arr2 = [
{id: 0, name: "Mark"},
{id: 4, name: "Sara"}
]
var res = arr1.reduce((acc, elem)=>{
var x = arr2.find(i=>i.id === elem.id);
if(x){
acc.push(x)
}else{
acc.push(elem)
}
return acc
}, []);
console.log(res)

Assuming you want to mutate the objects in arr1 rather than creating new ones, one way to do it would be using for...of to iterate the objects in arr2 and then check if there's already an object with the same id in arr1 using Array.prototype.find():
If there is one, you mutate it with Object.assign.
Otherwise, push the new object to arr1:
const arr1 = [
{ id: 0, name: 'John' },
{ id: 1, name: 'Sara' },
{ id: 2, name: 'Domnic' },
{ id: 3, name: 'Bravo' },
];
const arr2 = [
{ id: 0, name: 'Mark', sometingElse: 123 },
{ id: 2, foo: 'bar' },
{ id: 4, name: 'Sara' },
];
for (const currentElement of arr2) {
let previousElement = arr1.find(el => el.id === currentElement.id);
if (previousElement) {
Object.assign(previousElement, currentElement);
} else {
arr1.push(currentElement);
}
}
console.log(arr1);
.as-console-wrapper {
max-height: 100% !important;
}

if you want to try something different you can use foreach and filter to achieve this
let arr1 = [
{id: 0, name: "John"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
]
let arr2 = [
{id: 0, name: "Mark"},
{id: 4, name: "Sara"}]
arr1.forEach(x=>{
arr2.forEach(y=>{
if(x.id==y.id){
x.name=y.name
}
})
})
arr2.filter((a)=>{if(!arr1.some(b=>a.id==b.id)) arr1.push(a)})
console.log(arr1)

You should be able to use Array.prototype.find to sort this out!
let arr1 = [
{id: 0, name: "John"},
{id: 1, name: "Sara"},
{id: 2, name: "Domnic"},
{id: 3, name: "Bravo"}
];
let arr2 = [
{id: 0, name: "Mark"},
{id: 4, name: "Sara"}
];
let updateArrayOfObjects = (arr1, arr2) => {
for (let obj of arr2) {
let item = arr1.find(v => v.id === obj.id);
if (item) item.name = obj.name;
else arr1.push({ ...obj });
}
return arr1;
};
console.log(updateArrayOfObjects(arr1, arr2));

Related

Compare two array of objects and remove objects from first array if a property value is matched

I have 2 array of objects like
const arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
Here, I need to compare both these arrays and remove matching objects from arrayOne, which should finally give
this.arrayOne = [{id: 1, name: 'one'}];
I tried like below but it is removing all objects from the array
this.arrayOne = this.arrayOne.filter(o1 => this.arrayTwo.some(o2 => o1.id === o2.id));
What I am doing wrong here? Please suggest. Thanks
const arrayOne = [
{ id: 1, name: "one" },
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwo = [
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwoIds = new Set(arrayTwo.map((el) => el.id));
const arrayOneFiltered = arrayOne.filter((el) => !arrayTwoIds.has(el.id));
console.log(arrayOneFiltered);
// [ { id: 1, name: 'one' } ]
Depending on the size of the array, creating a set can improve performance, as you do not need to loop over arrayTwo arrayOne.length times but only once. After that, you can look up the existence of an id in arrayTwo in constant time.
Yet, as pointed out in another answer, this is not necessary if the arrays are small (like in your example). In this case, you could also use this one-liner:
arrayOne = arrayOne.filter((elOne) => !arrayTwo.some((elTwo) => elOne.id === elTwo.id));
Here, arrayOne would need to be mutable, i.e. defined with let.
You can find it by comparing it with id.
And arrayOne must be a let.
let arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
arrayOne = arrayOne.filter(one => !arrayTwo.find(two => one.id == two.id));
console.log(arrayOne);
const arrayOne = [{
id: 1,
name: 'one'
}, {
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwo = [{
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwoId = arrayTwo.map(el => (el.id)); // extract id from arrayTwo
const result = arrayOne.filter(el => !arrayTwoId.includes(el.id));
console.log(result);
Extract all the ids from the arrayTwo.
filter those objects who do not match the array of ids of arrayTwo.
Your way is correct. but you miss the not operation (!) before arrayTwo.some.
So the correct way is this:
const arrayOne = [
{id: 1, name: 'one'},
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
const arrayTwo = [
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
// Shared Items between arrayOne and arrayTwo (this what you done)
const sharedObjects = arrayOne.filter(o1 => arrayTwo.some(o2 => o1.id === o2.id));
console.log(sharedObjects);
// arrayOne - arrayTwo (this is what you want)
const arrayOneUniqueObjects = arrayOne.filter(o1 => !arrayTwo.some(o2 => o1.id === o2.id));
console.log(arrayOneUniqueObjects);
Also, You can find more details here:
bobbyhadz.com/blog/javascript-get-difference-between-two-arrays-of-objects

Remove equal objects from two arrays

I have the following problem in my ReactJs application. Let's say I have two arrays like this:
var cart = [
{id: 1, name: "item1"},
{id: 2, name: "item2"},
];
var productsArr = [
{proId: 1, category: 'cat1'},
{proId: 5, category: 'cat7'},
];
Is it possible to compare these 2 arrays and find any objects in productsArr which cart's id quals productsArr's proId and remove that object from only productsArr?
(If so, as I explained in this example, productsArr[0] should be removed.)
Thanks in advance.
You can use Array#filter in conjunction with Array#some.
var cart = [
{id: 1, name: "item1"},
{id: 2, name: "item2"},
];
var productsArr = [
{proId: 1, category: 'cat1'},
{proId: 5, category: 'cat7'},
];
productsArr = productsArr.filter(({proId})=>!cart.some(({id})=>proId === id));
console.log(productsArr);
var cart = [
{id: 1, name: "item1"},
{id: 2, name: "item2"},
];
var productsArr = [
{proId: 1, category: 'cat1'},
{proId: 5, category: 'cat7'},
];
for (var i = 0; i<productsArr.length; i++) {
if (cart.find(item => item.id === productsArr[i].proId)) {
productsArr.splice(i,1);
i--;
}
}
console.log(productsArr);

Remove same Values from array of Object

I want to remove same object from array by comparing 2 arrays.
Sample Data:
arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = []; // new array with with no same values it should be unique.
arr1.map((val, i)=>{
arr2.map((val2)=>{
if(val.id == val2.id){
console.log('Matched At: '+ i) // do nothing
}else{
newArray.push(val);
}
})
})
console.log(newArray); // e.g: [{id: 2, name: "b"}, {id: 3, name: "c"},];
Array.filter combined with not Array.some.
The trick here is also to not some,..
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
], arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const newArray=arr1.filter(a=>!arr2.some(s=>s.id===a.id));
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
As mentioned in comments the question could be interpreted slightly differently. If you also want the unqiue items from arr2, you basically just do it twice and join. IOW: check what not in arr2 is in arr1, and then check what not in arr1 that's in arr2.
eg..
const notIn=(a,b)=>a.filter(f=>!b.some(s=>f.id===s.id));
const newArray=[...notIn(arr1, arr2), ...notIn(arr2, arr1)];
Update 2:
Time complexity, as mentioned by qiAlex there is loops within loops. Although some will short circuit on finding a match, if the dataset gets large things could slow down. This is were Set and Map comes in.
So to fix this using a Set.
const notIn=(a,b)=>a.filter(a=>!b.has(a.id));
const newArray=[
...notIn(arr1, new Set(arr2.map(m=>m.id))),
...notIn(arr2, new Set(arr1.map(m=>m.id)))
];
const isInArray = (arr, id, name) => arr.reduce((result, curr) => ((curr.name === name && curr.id === id) || result), false)
const newArray = arr1.reduce((result, curr) => (isInArray(arr2, curr.id, curr.name) ? result : result.concat(curr)), [])
You can update you code using filter() method, instead of using .map() method like:
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
], arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = []; // new array with with no same values it should be unique.
newArray = arr1.filter(function(a) {
for(var i=0; i < arr2.length; i++){
if(a.id == arr2[i].id) return false;
}
return true;
});
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You check each element in first array whether its id lies in the second array by using Array.prototype.some. If the element is not present then only yield it.
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
const arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const result = arr1.filter(x => !arr2.some(y => y.id === x.id));
console.log(result);
I think a simple comparer can works for getting differences and then concat them.
with this method you dont need to check which array is bigger.
arr1 = [ {id: 1, name: "a"}, {id: 2, name: "b"}, {id: 3, name: "c"}, {id: 4, name: "d"}];
arr2 = [ {id: 1, name: "a"}, {id: 4, name: "d"},];
function localComparer(b){
return function(a){
return b.filter(
function(item){
return item.id == a.id && item.name == a.name
}).length == 0;
}
}
var onlyInArr1 = arr1.filter(localComparer(arr2));
var onlyInArr2 = arr2.filter(localComparer(arr1));
console.log(onlyInArr1.concat(onlyInArr2));
We can filter values by checking whether some element is not contained in current array:
const result = arr1.reduce((a, c) => {
if (!arr2.some(a2 => a2.id === c.id))
a.push(c);
return a;
}, [])
An example:
let arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
let arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const result = arr1.reduce((a, c) => {
if (!arr2.some(a2 => a2.id === c.id))
a.push(c);
return a;
}, [])
console.log(result);
Try this one -
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
const arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const arr3 = [...arr1, ...arr2];
const mySubArray = _.uniq(arr3, 'id');
console.log(mySubArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
So many loops in every answer.
Complexity of the code my answer is 2N,
Idea is:
to merge arrays.
first loop - mark duplicates somehow
second loop - filter duplicates out
arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = [...arr1, ...arr2].reduce((acc, item, index) => {
acc.items.push(item);
if (typeof acc.map[item.id] !== 'undefined') {
acc.items[acc.map[item.id]] = null;
acc.items[index] = null;
}
acc.map[item.id] = index;
return acc
}, {map: {}, items: []}).items.filter(item => !!item)
console.log(newArray);

Javascript concat and overwrite where element has the same id

Is it possible to concat two arrays with objects and let the second array overwrite the first array where they have the same id:
// array 1
[
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
]
// array 2:
[
{id: 1, name: "newFoo"},
{id: 4, name: "y"},
{id: 5, name: "z"}
]
// out:
[
{id: 1, name: "newFoo"}, // overwriten by array 2
{id: 2, name: "bar"}, // not changed (from array 1)
{id: 3, name: "baz"}, // not changed (from array 1)
{id: 4, name: "y"}, // added (from array 2)
{id: 5, name: "z"} // added (from array 2)
]
If it is possible I would like to do this without the use of third party libraries
var a = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
];
var b = [
{id: 1, name: "fooboo"},
{id: 4, name: "bar"},
{id: 5, name: "baz"}
];
/* iterate through each of b, if match found in a, extend with that of a. else push into b ...*/
b.forEach(m => {
var item = a.find(n => n.id === m.id);
if(item) { return Object.assign(item, m); }
a.push(m);
});
console.log(a);
You can do
let arr1 = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
]
let arr2 = [
{id: 1, name: "newFoo"},
{id: 4, name: "y"},
{id: 5, name: "z"}
]
let result = arr1.concat(arr2).reduce((a, b) => {
a[b.id] = b.name;
return a;
},{})
result = Object.keys(result).map(e => {
return {id : e, name : result[e]};
});
console.log(result);
Explanation
I am using the property of objects that they don't keep duplicate keys, so for an array concated together, I reduce it to an object with id as it's key and name as its value, hence overriding all duplicates. In the next step I converted this back into an array.
Check you my solution. There is no "rewrite", i just use a second array as base and don't write value if it has same id.
let a = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
];
let b = [
{id: 1, name: "newFoo"},
{id: 4, name: "y"},
{id: 5, name: "z"}
];
let duplicateId;
a.forEach(aitem => {
duplicateId = false;
b.forEach(bitem => {
if (aitem.id === bitem.id)
duplicateId = true;
});
if (!duplicateId)
b.push(aitem);
});
console.log(b);
Maybe you can use Object.assign and Object.entries to achieve, lets say:
const arr1 = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
]
const arr2 = [
{id: 1, name: "newFoo"},
{id: 4, name: "y"},
{id: 5, name: "z"}
]
const obj3 = Object.entries(Object.assign({}, ...arr1, arr2))
.map(([prop, value]) => ({[prop]:value}));
Example:
https://jsfiddle.net/0f75vLka/
Another option would be to convert arrays to map with id as key then merge the objects and then convert it back to array.
var arr1 = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
];
var arr2 = [
{id: 1, name: "newFoo"},
{id: 4, name: "y"},
{id: 5, name: "z"}
];
function arr2map(arr) {
var map = {};
for (var i = 0; i < arr.length; i++) {
var item = arr[i];
map[item.id] = item;
}
return map;
}
function map2arr(map) {
var arr = [];
for (var i in map) {
arr.push(map[i]);
}
return arr;
}
var arr1m = arr2map(arr1);
var arr2m = arr2map(arr2);
var arr3m = map2arr( Object.assign({}, arr1m, arr2m) );
//output
alert(JSON.stringify(arr3m));

Set order to array of object in javascript

I need to find a simplest way for setting order to array of objects.
For example, there is an array:
var array = [
{id: 1, name: "Matt"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"},
{id: 4, name: "Bruce"}
];
and I have provided
var order = [1,4,2,3];
which refers to object id property of array items.
Now I need to reorder array so it should be like:
var array = [
{id: 1, name: "Matt"},
{id: 4, name: "Bruce"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"}
]
Use Array#sort method for sorting and inside custom sort function use Array#indexOf method to get index.
var array = [{
id: 1,
name: "Matt"
}, {
id: 2,
name: "Jack"
}, {
id: 3,
name: "Morgan"
}, {
id: 4,
name: "Bruce"
}];
var order = [1, 4, 2, 3];
array.sort(function(a, b) {
// sort based on the index in order array
return order.indexOf(a.id) - order.indexOf(b.id);
})
console.log(array);
You can also use reduce() on [1,4,2,3] array to return object where keys will be elements and values will be index of each element and then sort by that object.
var array = [
{id: 1, name: "Matt"},
{id: 2, name: "Jack"},
{id: 3, name: "Morgan"},
{id: 4, name: "Bruce"}
];
var s = [1,4,2,3].reduce((r, e, i) => {return r[e] = i, r}, {});
var result = array.sort(function(a, b) {
return s[a.id] - s[b.id];
});
console.log(result)
I guess anything that involves sort can not be more efficient than an O(2n) solution. So i would like to do this job with two reduces as follows;
var arr = [{id: 1, name: "Matt"}, {id: 2, name: "Jack"}, {id: 3, name: "Morgan"}, {id: 4, name: "Bruce"}],
order = [1,4,2,3],
lut = order.reduce((t,e,i) => (t[e] = i,t),{}),
result = arr.reduce((res,obj) => (res[lut[obj.id]] = obj, res) ,[]);
console.log(result);

Categories