Reputation: 25
I am trying to combine these two arrays of objects together and get the output below.
userid
property should be unique but not name
or role
Input
const first = [
{ userid: 2, name: "Velen" },
{ userid: 56, name: "Illidan" },
{ userid: 23, name: "Muradin" },
{ userid: 12, name: "Sylvanas" },
{ userid: 44, name: "Cenarius" },
{ userid: 4, name: "Gul'Dan" },
];
const second = [
{ userid: 2, role: "Mage" },
{ userid: 4, role: "Worlock" },
{ userid: 56, role: "Demon Hunter" },
{ userid: 66, role: "Druid" },
{ userid: 87, role: "Shaman" },
{ userid: 12, role: "Hunter" },
];
Output
[
{ name: 'Velen', role: 'Mage', userid: 2 },
{ name: "Gul'Dan", role: 'Worlock', userid: 4 },
{ name: 'Sylvanas', role: 'Hunter', userid: 12 },
{ name: 'Muradin', role: null, userid: 23 },
{ name: 'Cenarius', role: null, userid: 44 },
{ name: 'Illidan', role: 'Demon Hunter', userid: 56 },
{ name: null, role: 'Druid', userid: 66 },
{ name: null, role: 'Shaman', userid: 87 }
]
I tried this solution but it didn't work:
const solution = (first, second) => {
first.sort((a, b) => a.userid - b.userid);
second.sort((a, b) => a.userid - b.userid);
first.map((item, idx) => {
return {
a: (item.role = second[idx].role),
b: (item.userid = second[idx].userid),
};
});
return first;
};
console.log(solution(first, second));
Upvotes: 0
Views: 95
Reputation: 341
You could do it using a reduce
function as follow:
// adding empty model to make sure we'll get all keys
const emptyObj = {role: null, name: null}
const emptyObj = {role: null, name: null}
const userids = [...new Set([...first, ...second].map(item => item.userid))]
const output = userids.reduce((acc, cur) => {
return [...acc, {...emptyObj, ...cur, ...(second.find(({userid}) => userid === cur ) ?? {}), ...(first.find(({userid}) => userid === cur ) ?? {})}]
}, [])
Upvotes: 0
Reputation: 668
This is the best I could think of using reduce, had to use two of them to achieve the wanted result. Assuming the first array always contains userid
and name
while the second array always contains userid
and role
.
const first = [
{ userid: 2, name: "Velen" },
{ userid: 56, name: "Illidan" },
{ userid: 23, name: "Muradin" },
{ userid: 12, name: "Sylvanas" },
{ userid: 44, name: "Cenarius" },
{ userid: 4, name: "Gul'Dan" },
];
const second = [
{ userid: 2, role: "Mage" },
{ userid: 4, role: "Worlock" },
{ userid: 56, role: "Demon Hunter" },
{ userid: 66, role: "Druid" },
{ userid: 87, role: "Shaman" },
{ userid: 12, role: "Hunter" },
];
const solution = (first, second) => {
const firstReduce = first.reduce((acc, curr) => {
const roleElem = second.find(elem => elem.userid === curr.userid);
if (roleElem) {
return [...acc, {...curr, role: roleElem.role}];
}
return [...acc, {...curr, role: null}];
}, []);
const secondReduce = second.reduce((acc, curr) => {
const elem = firstReduce.find(elem => elem.userid === curr.userid);
if (!elem) {
return [...acc, {...curr, name: null}];
}
return acc;
}, firstReduce);
return secondReduce;
}
console.log(solution(first, second));
Upvotes: 0
Reputation: 386868
You could reduce with an object and take a default object with nullified values.
const
first = [{ userid: 2, name: "Velen" }, { userid: 56, name: "Illidan" }, { userid: 23, name: "Muradin" }, { userid: 12, name: "Sylvanas" }, { userid: 44, name: "Cenarius" }, { userid: 4, name: "Gul'Dan" }],
second = [{ userid: 2, role: "Mage" }, { userid: 4, role: "Worlock" }, { userid: 56, role: "Demon Hunter" }, { userid: 66, role: "Druid" }, { userid: 87, role: "Shaman" }, { userid: 12, role: "Hunter" }],
result = Object.values([...first, ...second].reduce((r, o) => {
Object.assign(r[o.userid] ??= { name: null, role: null }, o);
return r;
}, {}));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 3
Reputation: 24324
In this kind of situation it's great to use Maps/Dictionary/ (key/value) data structure in general. Where the key is the userid in this situation and the value are the attributes you want to store.
const first = [
{ userid: 2, name: "Velen" },
{ userid: 56, name: "Illidan" },
{ userid: 23, name: "Muradin" },
{ userid: 12, name: "Sylvanas" },
{ userid: 44, name: "Cenarius" },
{ userid: 4, name: "Gul'Dan" },
];
const second = [
{ userid: 2, role: "Mage" },
{ userid: 4, role: "Worlock" },
{ userid: 56, role: "Demon Hunter" },
{ userid: 66, role: "Druid" },
{ userid: 87, role: "Shaman" },
{ userid: 12, role: "Hunter" },
];
const solution = (first, second) => {
const combined = new Map();
for (const item of first) {
combined.set(item.userid, { ...item, role: null });
}
for (const item of second) {
if (combined.has(item.userid)) {
combined.get(item.userid).role = item.role;
} else {
combined.set(item.userid, { ...item, name: null });
}
}
return Array.from(combined.values()).sort((a, b) => a.userid - b.userid);
};
console.log(solution(first, second));
In the end we sort using userid like what you tried to do.
Without the sort the time complexity of the solution is O(n)
. With the sort it's O(n*log(n))
.
Upvotes: 0