Reputation: 483
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)
Upvotes: 1
Views: 112
Reputation: 11
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);
Upvotes: 1
Reputation: 16454
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/[email protected]/lodash.min.js"></script>
Upvotes: 1
Reputation: 122037
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)
Upvotes: 1
Reputation: 99
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);
Upvotes: 0
Reputation: 5054
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);
Upvotes: 1
Reputation: 201
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]};
})
Upvotes: 1
Reputation: 44
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);
}
});
Upvotes: 1
Reputation: 4470
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)
Upvotes: 2