I guess have a dead simple problem but still didn't find a solution I have an array which looks like this:
var originalArray = [
{
pid: 1,
coordinates: {x: "50", y: null, f: null}
},
{
pid: 1,
coordinates: {x: null, y: "22", f: null}
},
{
pid: 1,
coordinates: {x: null, y: null, f: "2"}
},
{
pid: 2,
coordinates: {x: "23", y: null, f: null}
},
{
pid: 2,
coordinates: {x: null, y: "62", f: null}
},
{
pid: 2,
coordinates: {x: null, y: null, f: "15"}
}
]
I'd like to modify it to look like this (merge by id and join elements):
var originalArray = [
{
pid: 1,
coordinates: {x: "50", y: "22", f: "2"}
},
{
pid: 2,
coordinates: {x: "23", y: "62", f: "15"}
}
]
I already had multiple tries but still didn't find an elegant way of doing it.
CodePudding user response:
You can group the array by pid
s and merge the non null coordinates
using reduce
.
const originalArray = [
{ pid: 1, coordinates: { x: "50", y: null, f: null } },
{ pid: 1, coordinates: { x: null, y: "22", f: null } },
{ pid: 1, coordinates: { x: null, y: null, f: "2" } },
{ pid: 2, coordinates: { x: "23", y: null, f: null } },
{ pid: 2, coordinates: { x: null, y: "62", f: null } },
{ pid: 2, coordinates: { x: null, y: null, f: "15" } },
];
const result = Object.values(
originalArray.reduce((r, o) => {
r[o.pid] ??= { pid: o.pid };
r[o.pid].coordinates = {
...r[o.pid].coordinates,
...Object.entries(o.coordinates).reduce(
(r, [k, v]) => (v && (r[k] = v), r),
{}
),
};
return r;
}, {})
);
console.log(result);
Relevant Documentations:
CodePudding user response:
const input = [
{ pid: 1, coordinates: { x: "50", y: null, f: null } },
{ pid: 1, coordinates: { x: null, y: "22", f: null } },
{ pid: 1, coordinates: { x: null, y: null, f: "2" } },
{ pid: 2, coordinates: { x: "23", y: null, f: null } },
{ pid: 2, coordinates: { x: null, y: "62", f: null } },
{ pid: 2, coordinates: { x: null, y: null, f: "15" } },
];
const mergeByIdWhereEntry = (array, id, entries, predicate) => Array.from(
array.reduce(
(entriesById, { [id]: key, [entries]: value }) => entriesById.set(
key,
Object.assign(
entriesById.get(key) ?? {},
Object.fromEntries(
Object.entries(value).filter(predicate),
),
),
),
new Map(),
),
([key, value]) => ({ [id]: key, [entries]: value }),
);
const output = mergeByIdWhereEntry(input, 'pid', 'coordinates', (entry) => entry[1]);
console.log(output);
Here's one way to merge by an id and join the elements. It reduces the array into a Map of each merged coordinates by pid, then converts the map back into an array of the object in the original form.