Merge nested array in object in Javascript - javascript

I need to merge 2 objects with nested arrays
var dest = {
id: "865",
arr: [{
id: "123",
value: "First" }]
};
var src = {
id: "865",
arr: [{
id: "456",
value: "Second" }]
};
to produce
merge = {
id: "865",
arr: [{id: "123",
value: "First"},
{id: "456",
value: "Second"}]
};
I tried using _.merge(dest, src) (using Lodash) and a couple of other methods, but seems like the 2nd object is overwriting the first one because it doesn't handle the nested array the way I want.
What is the best way to do this?
Thanks,

You can use Lodash _.mergeWith method:
var dest = {
id: "865",
arr: [{
id: "123",
value: "First"
}]
};
var src = {
id: "865",
arr: [{
id: "456",
value: "Second"
}]
};
var merge = _.mergeWith({}, src, dest, function(a, b) {
if (_.isArray(a)) {
return b.concat(a);
}
});
console.log(merge);
It allows you to pass a customizer in order to merge the array in a "custom" way.
Here's the fiddle. Hope it helps.

You can use Object.assign()
var dest = {
id: "865",
arr: [{
id: "123",
value: "First" }]
};
var src = {
id: "865",
arr: [{
id: "456",
value: "Second" }]
};
var merge = Object.assign({}, dest);
merge.arr.push(Object.assign({}, src.arr[0]));
src.arr[0].id = 789; // should not affect `merge.arr`
console.log(merge);

Without any libraries.
var dest = {
id: "865",
arr: [{
id: "123",
value: "First"
}]
};
var src = {
id: "865",
arr: [{
id: "456",
value: "Second"
}]
};
// 1
var resultOne = {
id: dest.id,
arr: src.arr.concat(dest.arr)
};
// 2
var resultTwo = Object.assign({}, src, {
arr: src.arr.concat(dest.arr)
});
// 3
var merge = function(obj1, obj2) {
return Object.keys(obj1).reduce(function(result, next) {
if (Array.isArray(obj1[next]) && Array.isArray(obj2[next])) {
result[next] = obj1[next].concat(obj2[next]);
} else if (obj1[next] && obj2[next]) {
result[next] = obj2[next];
}
return result;
}, {});
}
console.log(merge(src, dest));

Related

ES6 map.has is not a function when called in a reducer

I want to return an array of objects without any duplicate ids. If there are any, then take the first one we see. So, we should NOT see {id: "2", value: '10'}. Instead, the value should be "Italian". I have this code below, but I am getting an map.has is not a function error.
const arr1 = [{
id: "1",
value: "English"
},
{
id: "2",
value: "Italian"
}
];
const arr2 = [{
id: "2",
value: '10'
},
{
id: "3",
value: "German"
}
];
const concatArr = arr1.concat(arr2);
const mergedArr = [...concatArr.reduce((map, obj) => map.has(obj.id) ? "" : map.set(obj.id, obj), new Map()).values()];
console.log(mergedArr);
You need to always return a map not an empty string when the thing is already in the map.
const arr1 = [{
id: "1",
value: "English"
},
{
id: "2",
value: "Italian"
}
];
const arr2 = [{
id: "2",
value: '10'
},
{
id: "3",
value: "German"
}
];
const concatArr = arr1.concat(arr2);
const mergedArr = [...concatArr.reduce((map, obj) => map.has(obj.id) ? map : map.set(obj.id, obj), new Map()).values()];
console.log(mergedArr);
You can use array#reduce to uniquely identify each object with unique id in an object accumulator and then extract all values from this object using Object.values().
const arr1 = [{ id: "1", value: "English" }, { id: "2", value: "Italian" } ],
arr2 = [{ id: "2", value: '10' }, { id: "3", value: "German" } ],
result = Object.values(arr1.concat(arr2).reduce((r, o) => {
r[o.id] = r[o.id] || o;
return r;
},{}));
console.log(result);

How filter array of objects based on objects exists in another array of objects?

I have
array1 = [{ name: sample1 }, { name: sample2 }, { name: sample3 }];
array2 = [{ name: sample1 }, { name: sample2 }];
I want to filter objects of array1 which exists in array2.
So I need to have
[{ name: sample1 }, { name: sample2 }]
How can I get it in javascript?
You can use .filter and .some function in JavaScript ,
Here is the example
const array1 = [{ name: "sample1" }, { name: "sample2" }, {
name: "sample3" }];
const array2 = [{ name: "sample1" }, { name: "sample2" }];
let Result = array1.filter(function(obj) {
return array2.some(function(obj2) {
return obj.name== obj2.name;
});
});
console.log(Result)
You can use object destructuring, the map() and .includes() methods as shown below:
const array1 = [{ name: "sample1" }, { name: "sample2" }, { name: "sample3" }];
const array2 = [{ name: "sample1" }, { name: "sample2" }];
const filtered = array1.filter(
({name}) => array2.map(o => o.name).includes(name)
);
console.log( filtered );

How can I create a JavaScript object from an array of objects?

I'm trying to get an array of objects into an object-format with the values as the keys of the new object.
Let's say I got this data:
const data = [
{
key: "foo",
value: "xyz",
classLabel: "Test"
},
{
key: "foo",
value: "abc",
classLabel: "Test"
},
{
key: "bar",
value: "aaa",
classLabel: "Test"
}]
And the format I want to build is like this:
const expected = {
foo: ["xyz", "abc"],
bar: ["aaa"]
}
The values are transferred to the keys and pushed into the same array for duplicate keys.
So far I only extracted the keys with:
const result = [...new Set(data.map(item => item.key))]; // ["foo", "bar"]
const data = [
{
key: "foo",
value: "xyz",
classLabel: "Test"
},
{
key: "foo",
value: "abc",
classLabel: "Test"
},
{
key: "bar",
value: "aaa",
classLabel: "Test"
}];
let expected = data.reduce((out, {key, value}) => {
out[key] = out[key] || [];
out[key].push(value);
return out;
}, {});
console.log(expected);
The following should work:
const data = [
{
key: "foo",
value: "xyz",
classLabel: "Test",
},
{
key: "foo",
value: "abc",
classLabel: "Test",
},
{
key: "bar",
value: "aaa",
classLabel: "Test",
},
];
const mapToObj = (arr) => {
let obj = {};
for (let i in arr) {
let objKey = arr[i].key;
obj[objKey]
? Object.assign(obj, { [arr[i].key]: [obj[objKey], arr[i].value] })
: Object.assign(obj, { [arr[i].key]: arr[i].value });
}
return obj;
};
console.log(mapToObj(data));

How to merge two array of objects by key AND keep unique keys in a single array of objects?

I want to merge two array of objects where objects with the same ID will merge properties and objects with unique IDs will be its own object in the merged array. The following code does the first part where similar IDs will merge but how do I keep objects with unique ids from arr2 in the merged array and have it work with arrays of varying lengths?
Expected output:
[
{
"id": "1",
"date": "2017-01-24",
"name": "test"
},
{
"id": "2",
"date": "2017-01-22",
"bar": "foo"
}
{ "id": "3",
"foo": "bar",
}
]
The code:
let arr1 = [{
id: '1',
createdDate: '2017-01-24'
},
{
id: '2',
createdDate: '2017-01-22'
},
];
let arr2 = [{
id: '1',
name: 'test'
},
{
id: '3',
foo: 'bar'
},
{
id: '2',
bar: 'foo'
},
];
let merged = [];
for (let i = 0; i < arr1.length; i++) {
merged.push({
...arr1[i],
...arr2.find((itmInner) => itmInner.id === arr1[i].id),
},
);
}
console.log(merged);
Iterate over the larger array, the one that contains the smaller array, instead:
let arr1=[{id:"1",createdDate:"2017-01-24"},{id:"2",createdDate:"2017-01-22"}],arr2=[{id:"1",name:"test"},{id:"3",foo:"bar"},{id:"2",bar:"foo"}];
const merged = arr2.map(item => ({
...arr1.find(({ id }) => id === item.id),
...item
}));
console.log(merged);
(if order matters, you can sort if afterwards too)
If you don't know in advance which one / if one will contain the other, then use an object to index the merged objects by IDs first:
let arr1=[{id:"1",createdDate:"2017-01-24"},{id:"2",createdDate:"2017-01-22"}],arr2=[{id:"1",name:"test"},{id:"3",foo:"bar"},{id:"2",bar:"foo"}];
const resultObj = Object.fromEntries(
arr1.map(
item => [item.id, { ...item }]
)
);
for (const item of arr2) {
if (!resultObj[item.id]) {
resultObj[item.id] = item;
} else {
Object.assign(resultObj[item.id], item);
}
}
const merged = Object.values(resultObj);
console.log(merged);
You can create new object that contains the elems of arr1 and arr2 group by id key as follows and the merged array will be stored on object values.
You can get object values using Object.values func.
let arr1 = [{
id: '1',
createdDate: '2017-01-24'
},
{
id: '2',
createdDate: '2017-01-22'
},
];
let arr2 = [{
id: '1',
name: 'test'
},
{
id: '3',
foo: 'bar'
},
{
id: '2',
bar: 'foo'
},
];
const groupById = {};
for (let i = 0; i < Math.min(arr1.length, arr2.length); i ++) {
if (arr1[i]) {
groupById[arr1[i].id] = { ...groupById[arr1[i].id], ...arr1[i] };
}
if (arr2[i]) {
groupById[arr2[i].id] = { ...groupById[arr2[i].id], ...arr2[i] };
}
}
const merged = Object.values(groupById);
console.log(merged);
You could take a single loop approach by storing the objects in a hash table, sorted by id.
const
mergeTo = (target, objects = {}) => o => {
if (!objects[o.id]) target.push(objects[o.id] = {});
Object.assign(objects[o.id], o);
},
array1 = [{ id: '1', createdDate: '2017-01-24' }, { id: '2', createdDate: '2017-01-22' }],
array2 = [{ id: '1', name: 'test' }, { id: '3', foo: 'bar' }, { id: '2', bar: 'foo' }],
merged = [],
merge = mergeTo(merged);
array1.forEach(merge);
array2.forEach(merge);
console.log(merged);
.as-console-wrapper { max-height: 100% !important; top: 0; }
A different approach could be merged the two array as is, and then "squash" it:
let arr1 = [{
id: '1',
createdDate: '2017-01-24'
},
{
id: '2',
createdDate: '2017-01-22'
},
];
let arr2 = [{
id: '1',
name: 'test'
},
{
id: '3',
foo: 'bar'
},
{
id: '2',
bar: 'foo'
},
];
let merged = [...arr1, ...arr2].reduce(
(acc, {id, ...props}) =>
(acc.set(id, {...(acc.get(id) || {}), ...props}), acc), new Map());
console.log([...merged].map( ([id, props]) => ({id, ...props}) ))
Notice that you might not need the last line, it used just to obtain the format you want to, since the above reduce is using a Map as accumulator, you can already access to everything with just merged.get("1").createdDate for example (where "1" is the id).
Since you're operating on one array by merging them at the beginning, you don't care about the length of them or even which one contains more elements. You can also have several arrays instead of just two, it doesn't matter.
What it matters is the order: if more than one array contains the same property for the same "id", the value you'll get is the value from the most recent array added (in the example above, would be arr2).
You can write a function to reduce the arrays to an object and then extract the value from that object which will return the values that you want. You can see the code below:
let arr1 = [
{
id: '1',
createdDate: '2017-01-24',
},
{
id: '2',
createdDate: '2017-01-22',
},
];
let arr2 = [
{
id: '1',
name: 'test',
},
{
id: '3',
foo: 'bar',
},
{
id: '2',
bar: 'foo',
},
];
function merge(arr1 = [], arr2 = []) {
return Object.values(
arr1.concat(arr2).reduce(
(acc, curr) => ({
...acc,
[curr.id]: { ...(acc[curr.id] ?? {}), ...curr },
}),
{}
)
);
}
const merged = merge(arr1, arr2);
Output:
[
{
"id": "1",
"createdDate": "2017-01-24",
"name": "test"
},
{
"id": "2",
"createdDate": "2017-01-22",
"bar": "foo"
},
{
"id": "3",
"foo": "bar"
}
]

How to get distinct properties value from array? [duplicate]

This question already has answers here:
Remove duplicates form an array
(17 answers)
Closed 5 years ago.
I have this array?
var arr = [{id:"1",Name:"Tom"},
{id:"2",Name:"Jon"},
{id:"3",Name:"Tom"},
{id:"4",Name:"Jack"}]
From array above I need to fecth all existing Names distinct.
var result = getNamesDistinct(arr);
The result should contain result is:
["Tom","Jon","Jack"];
My question is how to get all existing Names from arr distinct?
If Set is available, you can simply do
new Set(arr.map(obj => obj.Name))
(pass the set to Array.from if you need an array)
You can do it via Set object
const arr = [
{ id: "1", Name: "Tom" },
{ id: "2", Name: "Jon" },
{ id: "3", Name: "Tom" },
{ id: "4", Name: "Jack" }
];
const uniqueNames = [...new Set(arr.map(item => item.Name))];
console.log(uniqueNames);
Or you can iterate over the array and add condition to get only unique names.
const arr = [
{ id: "1", Name: "Tom" },
{ id: "2", Name: "Jon" },
{ id: "3", Name: "Tom" },
{ id: "4", Name: "Jack" }
];
const uniqueNames = arr.reduce(function(arr, item) {
if(arr.indexOf(item.Name) === -1) {
arr.push(item.Name);
}
return arr;
}, []);
console.log(uniqueNames);
you can try this
var array = [{
id: "1",
Name: "Tom"
}, {
id: "2",
Name: "Jon"
}, {
id: "3",
Name: "Tom"
}, {
id: "4",
Name: "Jack"
}]
function uniqueNames(array) {
var newArray = [];
array.forEach((value, key) => {
newArray.push(value.Name)
});
return newArray
}
var myNewArray = uniqueNames(array)

Categories

Resources