Merge 2 objects in an array where the values are an array - javascript

I am trying to merge values in 2 objects from the same array. The objects in this case are similar and the values I want to merge are arrays(Set)
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
Expected Output
[
{
name: "foo1",
value: ["val1","val2", "val3"]
},{
name: "foo2",
value: ["val4","val4", "val5"]
}
]
My Code
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
let newValue = new Set(output[existingIndex].value).add(item.value)
output[existingIndex].value = Array.from(newValue);
} else {
output.push(item);
}
});
Output Gotten
[ {
name: "foo1",
value: ["val1", "val2", ["val2", "val3"]]
}, {
name: "foo2",
value: ["val4", ["val4", "val5"]]
}]
How can I get the expected output (ES6 would also be preferred)

Try this
const array = [
{
"name": "foo1",
"value": [
"val1",
"val2",
"val3"
]
},
{
"name": "foo1",
"value": [
"val2",
"val3"
]
},
{
"name": "foo2",
"value": [
"val4",
"val5"
]
},
{
"name": "foo2",
"value": [
"val4",
"val5"
]
}
]
const result = []
for (const item of array) {
const existingItem = result.find(i => i.name === item.name)
if (existingItem) {
existingItem.value = [...new Set([...existingItem.value, ...item.value])]
} else {
result.push(item)
}
}
console.log(result)

Is this code solve your problem?
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
var output = [];
array.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.name == item.name;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
let newValue = new Set(output[existingIndex].value.concat(item.value))
output[existingIndex].value = Array.from(newValue);
} else {
output.push(item);
}
});

try
var arr = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
var arr2={}
arr.map((elem,ind)=>{
if(!arr2[elem.name]){
arr2[elem.name]=[]
}
arr2[elem.name]=[...arr2[elem.name],...elem.value]
})
arr=Object.keys(arr2);
arr.map((elem,ind)=>{
arr[ind]={name:elem,value:arr2[elem]};
})

You can do the following using reduce,
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
res = array.reduce((prev, curr) => {
let index = prev.findIndex(item => item.name === curr.name);
if(index > -1) {
s = new Set([...prev[index].value, ...curr.value]);
prev[index].value = Array.from(s);
} else {
prev.push(curr);
}
return prev;
},[]);
console.log(res);

You could use reduce method with a Map as accumulator value and then use spread syntax ... on Map values to get an array of values.
var array = [{"name":"foo1","value":["val1","val2","val2","val3"]},{"name":"foo1","value":["val2","val3"]},{"name":"foo2","value":["val4","val4","val5"]},{"name":"foo2","value":["val4","val5"]}]
const map = array.reduce((r, { name, value }) => {
if (!r.has(name)) r.set(name, { name, value })
else r.get(name).value.push(...value)
r.get(name).value = [...new Set(r.get(name).value)]
return r;
}, new Map)
const result = [...map.values()]
console.log(result)

One approach is to create an unique list of keys and iterate over it. Create an array for each key and merge the values. The vanilla js way is:
Array.from(new Set(array.map(el => el.name)))
.map(name => ({
name,
value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
}))
Example:
const array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
console.log(Array.from(new Set(array.map(el => el.name)))
.map(name => ({
name,
value: Array.from(new Set(array.filter(el => el.name === name).flatMap(el => el.value)))
})));
Using lodash you can reduce it to
_.uniq(array.map(el => el.name))
.map(name => ({
name,
value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
}))
Example:
const array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
console.log(_.uniq(array.map(el => el.name))
.map(name => ({
name,
value: _.uniq(array.filter(el => el.name === name).flatMap(el => el.value))
})));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.20/lodash.min.js"></script>

Find unique values of keys. Match this keys within array and return unique objects. Push this objects in an empty array. Then match other objects value with the new arrays objects value and push the unmatched values to this new array.
var arr = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
let key = [];
arr.map((val)=>key.push(val.name));
let uniquekeys = [...new Set(key)]; //unique values of keys
let newarr = [];
uniquekeys.map((uniquekey,ind)=>{
let reduceunique = arr.filter((vals)=>uniquekey == vals.name); // return matching objects as array
newarr.push(reduceunique[0]); // Push unique objects in an empty array
for(let i = 1; i<uniquekeys.length;i++){
reduceunique[i].value.map((val)=>{
let existvalue = newarr[ind].value.indexOf(val); // Match every value with the unique objects values
if(existvalue<0){
newarr[ind].value.push(val); // push the unmatched value in the array
}
});
};
});
console.log(newarr);

try to use Array.reduce and Array.filter to get the result like the following
var array = [
{
name: "foo1",
value: ["val1","val2"]
},
{
name: "foo1",
value: ["val2", "val3"]
},
{
name: "foo2",
value: ["val4"]
},
{
name: "foo2",
value: ["val4","val5"]
},
];
res = array.reduce((prev, curr) => {
let index = prev.findIndex(item => item.name === curr.name);
if(index > -1) {
prev[index].value = [...prev[index].value, ...curr.value];
prev[index].value = prev[index].value.filter((v,i) => prev[index].value.indexOf(v) === i)
} else {
prev.push(curr);
}
return prev;
},[]);
console.log(res);

Related

How to filter array of array objects?

Trying to filter array of array objects. when variable matches with array of object value of dropDownOne key 'filterValue', then it will return dropDownTwo array,
let testName = ‘ filterValue’
var nestedArray = [
[
{
dropDownOne: {
key: "filterValue",
value: "test1"
},
dropDownTwo: [
{
key: "retrieveArrKey1",
value: "test123"
},
{
key: "retrieveArrKey2",
value: "test345"
}
]
}
],
[
{
dropDownOne: {
key: "NoFilter",
value: "test2"
},
dropDownTwo: [
{
key: "dropDown2",
value: "test"
},
{
key: "dropDown3",
value: "test"
}
]
}
]
]
Output =
dropDownTwo:[
{
key: "retrieveArrKey1",
value: "test123"
},
{
key: "retrieveArrKey2",
value: "test345"
}
]
Tried with this
let filterObj = nestedArray.filter((arr => arr.filter(value => {
if (value[0].dropDownOne.key === 'filterValue') {
return arr[1];
}
}))
But did not get the correct result
We can use Array.flat() and Array.flatMap() combined with Array.filter() to do it
let result = nestedArray.flat().filter(e => e.dropDownOne.key === testName).flatMap(e => e.dropDownTwo)
console.log(result)
let testName = `filterValue`
var nestedArray = [
[
{
dropDownOne: {
key: "filterValue",
value: "test1"
},
dropDownTwo: [
{
key: "retrieveArrKey1",
value: "test123"
},
{
key: "retrieveArrKey2",
value: "test345"
}
]
}
],
[
{
dropDownOne: {
key: "NoFilter",
value: "test2"
},
dropDownTwo: [
{
key: "dropDown2",
value: "test"
},
{
key: "dropDown3",
value: "test"
}
]
}
]
]
let result = nestedArray.flat().filter(e => e.dropDownOne.key === testName).flatMap(e => e.dropDownTwo)
console.log(result)
You can do it in this way :
nestedArray.filter(arr => arr.find(item=> item.dropDownOne.key === 'filterValue'))[0][0].dropDownTwo
var nestedArray = [
[
{
dropDownOne: {
key: "filterValue",
value: "test1"
},
dropDownTwo: [
{
key: "retrieveArrKey1",
value: "test123"
},
{
key: "retrieveArrKey2",
value: "test345"
}
]
}
],
[
{
dropDownOne: {
key: "NoFilter",
value: "test2"
},
dropDownTwo: [
{
key: "dropDown2",
value: "test"
},
{
key: "dropDown3",
value: "test"
}
]
}
]
]
const result = nestedArray.filter(arr => arr.find(item=> item.dropDownOne.key === 'filterValue'))[0][0].dropDownTwo
console.log(result)
You could use both flat() to flatten the nestedArray, then use the find() method to find the object with a dropDownOne.key that matches the value of testName.
it should then return the dropDownTwo property of that object.
let result = nestedArray.flat().find(obj => obj.dropDownOne.key === testName);
let filterObj = result ? result.dropDownTwo : [];
console.log(filterObj);
a full running example:
let testName = 'filterValue';
var nestedArray = [
[{
dropDownOne: {
key: "filterValue",
value: "test1"
},
dropDownTwo: [{
key: "retrieveArrKey1",
value: "test123"
},
{
key: "retrieveArrKey2",
value: "test345"
}
]
}],
[{
dropDownOne: {
key: "NoFilter",
value: "test2"
},
dropDownTwo: [{
key: "dropDown2",
value: "test"
},
{
key: "dropDown3",
value: "test"
}
]
}]
]
let result = nestedArray.flat().find(obj => obj.dropDownOne.key === testName);
let filterObj = result ? result.dropDownTwo : [];
console.log(filterObj);
Don't like other solutions due to too many array iterations. You could make a single run using reduce function which is a grandfather of many JS Array functions. It looks a bit worse than flat-filter-flat-..., but will probably work way faster due to much lower array iterations.
const testName = 'filterValue';
const nestedArray = [
[{
dropDownOne: {key: 'filterValue', value: 'test1'},
dropDownTwo: [
{key: 'retrieveArrKey1', value: 'test123'},
{key: 'retrieveArrKey2', value: 'test345'},
],
}],
[{
dropDownOne: {key: 'NoFilter', value: 'test2'},
dropDownTwo: [
{key: 'dropDown2', value: 'test'},
{key: 'dropDown3', value: 'test'},
],
}],
];
const result = nestedArray.reduce((acc, nestedItem) => {
nestedItem.forEach(item => {
if (item.dropDownOne.key === testName) {
acc.push(item.dropDownTwo);
}
});
return acc;
}, []);
console.log(result);

Removing Duplicates from Array of Objects

Hi I m trying to remove duplicates from array of object using id, but id's are null then the object should contain those null id's and remove others which are duplicate
Here is the array of objects example:
const arr = [
{
id: 6652,
value: "erger"
},
{
id: 6652,
value: "sdfs"
},
{
id: 6653,
value: "sdgdfg"
},
{
id: 6000,
value: "trgd"
},
{
id: 6667,
value: "asdf"
},
{
id: 6667,
value: "fdg"
},
{
id: 6668,
value: "dfgr"
},
{
id: null,
value: "fg"
},
{
id: null,
value: "dfgdf"
},
{
id: null,
value: "fg"
},
{
id: null,
value: "dfgdf"
}
];
Below is the finalResult
array = [{
id: 6652
value: "sdfs"
},
{
id: 6653
value: "sdgdfg"
},
{
id: 6000
value: "trgd"
},
{
id: 6667
value: "fdg"
},
{
id: 6668
value: "dfgr"
},
{
id: null
value: "fg"
},
{
id: null
value: "dfgdf"
},
{
id: null
value: "fg"
},
{
id: null
value: "dfgdf"
}
]
In the above result the 6652 and 6667 is removed as they were duplicates and but null id are kept as i don't want to remove the null id and remove other repeated values.
Below is the logic i am trying to use but it doesn't work if ids are null
array= array.filter((v,i,a)=>a.findIndex(t=>( v.id !== null && t.id === v.id ))===i)
const filterKeys = {};
const filtered = arr.reduce((acc, item) => {
if (item.id === null || !(item.id in filterKeys)) {
filterKeys[item.id] = true;
acc.push(item);
}
return acc;
}, []);
Create a separate object to keep track of object ids that have been encountered, filterKeys in this case.
Since array is an array, do a reduce to iterate over the array. If the id is nuil or not found in filterKeys, push the item to the accumulator and return it for the next iteration. Since we don't care about ids that are null, they don't have an effect and are thus not filtered out.
Use this below code I tested(working) with your array of objects :
arr.forEach(function (item) {
if (item.id == null) {
result.push(item);
}
else {
var index = result.findIndex(x => x.id == item.id);
if (index == -1)
{
result.push(item);
}
}
});
console.log(result)
You can try this out-
const array = [{ id: 6652, value: 'erger' },{ id: 6652, value: 'sdfs' },{ id: 6653, value: 'sdgdfg' },{ id: 6000, value: 'trgd' },{ id: 6667, value: 'asdf' },{ id: 6667, value: 'fdg' },{ id: 6668, value: 'dfgr' },{ id: null, value: 'fg' },{ id: null, value: 'dfgdf' },{ id: null, value: 'fg' },{ id: null, value: 'dfgdf' },];
let index = 0;
const result = Object.values(
array.reduce(
(acc, curr) =>
curr.id === null ? { ...acc, [index++]: curr } : { ...acc, [curr.id]: curr },
{}
)
);
console.log(result);
.as-console-wrapper {min-height: 100%; top: 0}

I want to merge values in an array if they have same id [duplicate]

This question already has answers here:
Group array items using object
(19 answers)
Closed 3 years ago.
I have an array Object which has same Id and different values. I need an output with same id and different values merged to the id.
Input:
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
Output:
result = [{
id: 1,
value: ['Honda', 'Benz']
}, {
id: 2,
value: ['Fiat', 'Porche']
}
Hope it will helps you. But this question is duplicate
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
var output = [];
data.forEach(function(item) {
var existing = output.filter(function(v, i) {
return v.id == item.id;
});
if (existing.length) {
var existingIndex = output.indexOf(existing[0]);
output[existingIndex].value = output[existingIndex].value.concat(item.value);
} else {
if (typeof item.value == 'string')
item.value = [item.value];
output.push(item);
}
});
console.dir(output);
const data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
const expectedResult = [{
id: 1,
value: ['Honda', 'Benz']
}, {
id: 2,
value: ['Fiat', 'Porche']
}
];
const result = [];
data.forEach((e, i) => {
const indexOfExisting = result.findIndex(x => x.id === e.id);
if (indexOfExisting === -1) {
result.push({
id: e.id,
value: [e.value]
})
} else {
result[indexOfExisting].value.push(e.value);
}
});
// console.log(result)
console.log(expectedResult)
You can use Array.prototype.reduce() to achieve it.
let data = [{
id: 1,
value: 'Honda'
},
{
id: 2,
value: 'Fiat'
},
{
id: 2,
value: 'Porche'
},
{
id: 1,
value: 'Benz'
}
];
let result = data.reduce((acc, ele) => {
let filtered = acc.filter(el => el.id == ele.id)
if (filtered.length > 0) {
filtered[0]["value"].push(ele.value);
} else {
element = {};
element["id"] = ele.id;
element["value"] = []
element["value"].push(ele.value);
acc.push(element)
}
return acc;
}, [])
console.log(result)

How to create an array based on two array

I have an array of object, this array contains differents names.
[ "Foo", "Bar", "Test", "Other" ];
And another array of object
[ { name:"Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 } ]
I need to create an array of them, the new array contains sub array with a size of 2, first index the name and second index the value.
The order of the array need to be the same of the first one (array of names).
Like
[ ["Foo", 120], ["Bar", 159], ["Test", undefined], ["Other", 1230] ]
So I try this code, but my output is not correct. The order of name is correct but the order of value is not.
var order = ["Foo", "Bar", "Test", "Other"];
var values = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }];
var array = order.map(function(name, i) {
return [name, (values[i] && values[i].value) ];
})
console.log(array)
You could take a Map and get the items in the wanted order.
var names = [ "Foo", "Bar", "Test", "Other" ],
objects = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }],
map = new Map(objects.map(({ name, value }) => [name, value])),
result = names.map(name => [name, map.get(name)])
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You're nearly there - you just need to find the correct value:
var order = ["Foo", "Bar", "Test", "Other"];
var values = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }];
var array = order.map(function(name, i) {
return [name, values.some(e => e.name == name) ? values.find(e => e.name == name).value : undefined];
})
console.log(array)
ES5 syntax:
var order = ["Foo", "Bar", "Test", "Other"];
var values = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }];
var array = order.map(function(name, i) {
return [name, values.some(function(e) {
return e.name == name;
}) ? values.find(function(e) {
return e.name == name;
}).value : undefined];
});
console.log(array)
Check out my solution. Hope this helps.
const a = [ "Foo", "Bar", "Test", "Other" ];
const b = [ { name:"Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 } ];
const res = a.map((item) => [ item, (b.find(({ name }) => name === item) || {}).value ])
console.log(res)
You need to use entries in "order" to lookup "name" in values
var order = ["Foo", "Bar", "Test", "Other"];
var values = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }];
var array = order.map(function(key, i) {
let found = values.find(({name}) => name === key);
return [key, found && found.value ];
})
console.log(array)
You could use map and take the Object.values of the found item, or a default one
const arr1 = [ "Foo", "Bar", "Test", "Other" ];
const arr2 = [ { name:"Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 } ];
const res = arr1.map(e => Object.values(arr2.find(({name}) => name === e) || ({name: e, value: undefined})));
console.log(res);
var order = ["Foo", "Bar", "Test", "Other"];
var values = [{ name: "Bar", value: 159 }, { name: "Foo", value: 120 }, { name: "Other", value: 1230 }];
var result = [];
orders.forEach((f) => {
let found = false;
values.forEach(s => {
if (f === s.name) {
result.push([f, s.value]);
found = true;
}
});
if (!found) {
result.push([f, undefined]);
}
});

merge javascript array values with same key

What is the best way to re-organize array into output? I need to merge the values with the same key into an array of objects.
the input array:
var array = [
{
aaa: {
name: "foo1",
value: "val1"
}
},
{
aaa: {
name: "foo2",
value: "val2"
}
},
{
bbb: {
name: "foo3",
value: "val3"
}
},
{
bbb: {
name: "foo4",
value: "val4"
}
}
];
The desired output:
var output = [
{
aaa:
[{
name: "foo1",
value: "val1"
},{
name: "foo2",
value: "val2"
}]
},
{
bbb:
[{
name: "foo3",
value: "val3"
},{
name: "foo4",
value: "val4"
}]
}
];
What would be the best way to achieve this?
Thanks in advance.
You can use reduce
var array = [{aaa: {name: "foo1",value: "val1"}},{aaa: {name: "foo2",value: "val2"}},{bbb: {name: "foo3",value: "val3"}},{bbb: {name: "foo4",value: "val4"}}];
var newArray = array.reduce((c, v) => {
for (var k in v) {
c[k] = c[k] || [];
c[k].push(v[k]);
}
return c;
}, {});
console.log(newArray);
Doc: reduce()
You can use reduce and forEach function.
var array = [{ aaa: { name: "foo1", value: "val1" } }, { aaa: { name: "foo2", value: "val2" } }, { bbb: { name: "foo3", value: "val3" } }, { bbb: { name: "foo4", value: "val4" } }];
var result = array.reduce((a, c) => {
Object.keys(c).forEach((k) => {
if (a[k]) {
a[k].push(c[k]);
} else {
a[k] = [c[k]];
}
})
return a;
}, {});
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories