0

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));

4 Answers 4

3

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; }

Sign up to request clarification or add additional context in comments.

Comments

0

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)).

2 Comments

that makes sense, when you run your solution look at the last two objects, role came before name unlike the objects before that
@Rio0o.dev JavaScript does not guarantee the order of properties in an object.
0

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));

Comments

0

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 ) ?? {})}]
}, [])

4 Comments

I like the idea of reduce method but when I ran your code is giving different output from the one I posted.
You are speaking about the missing null values? I edited my answer to meet your need!
it was not just about missing null, your solution is only giving the userid property of the first array, it not combining the second array userid, I am only getting 6 objects as output which they supposed to be 8 objects.
Ok, I'm sorry. Reworked it based on an array of userids so nothing is missing!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.