I have an array of objects that looks like:
const arr = [
{
"name": "Day",
"value": "Monday"
},
{
"name": "Month",
"value": "November"
},
{
"name": "Day",
"value": "Monday"
},
{
"name": "Month",
"value": "December"
},
{
"name": "Day",
"value": "Friday"
},
{
"name": "Month",
"value": "November"
},
{
"name": "Day",
"value": "Friday"
},
{
"name": "Month",
"value": "December"
}
]
but I'm needing to modify my array of objects to:
const final = [
{
"name": "Day",
"values": [
"Monday",
"Friday"
]
},
{
"name": "Month",
"values": [
"November",
"December"
]
}
]
I can filter out the duplicates with:
const filtered = arr.filter(
(v, i, a) =>
a.findIndex(v2 => v?.name === v2?.name && v?.value === v2?.value) === i
);
but I'm stuck on the approach on an efficient way to do this without Lodash or underscore and I've tried using Object.assign()
but my implementation isn't working:
const test = filtered.map(({ name, value }) =>
Object.assign({ name, value: [] }, (name, value))
);
console.log(test)
Thought I had seen this asked before and tested answers from:
In an array of objects and can I combine the objects with the same name but have the value in an array of strings?
Use reduce with a start value that has your days and moths elements preallocated, using a Set to automatically ignore duplicates, and then after you've reduced everything, converting that set into an array:
const arr = [{
name: "Day",
value: "Monday",
},{
name: "Month",
value: "November",
},{
name: "Day",
value: "Monday",
},{
name: "Month",
value: "December",
},{
name: "Day",
value: "Friday",
},{
name: "Month",
value: "November",
},{
name: "Day",
value: "Friday",
},{
name: "Month",
value: "December",
}];
// reduce the data to the form you need:
const final = arr.reduce(
(resultSoFar, {name, value}) => {
// find the "bin" to add this value to:
let bin = resultSoFar.find((e) => e.name === name);
// or make a new bin if there isn't one:
if (!bin) resultSoFar.push(bin = { name, values: new Set() });
// then add our value, and return the new result so far.
bin.values.add(value);
return resultSoFar;
},
// and start with `resultSoFar` being an empty array:
[]
);
// as last step, convert the sets into plain arrays:
final.forEach(e => e.values = [...e.values]);
// what did we get?
console.log(final);