0

I have a array like this:

let obj = [
    {
        id: 1,
        name: 'bob'
    },
        {
        id: 2,
        name: 'bob'
    },
        {
        id: 3,
        name: 'karl'
    },
        {
        id: 4,
        name: 'joe'
    },
        {
        id: 5,
        name: 'joe'
    },    {
        id: 6,
        name: 'rick'
    },
    
];

I need to write some javascript code to parse through the array and handle the duplicate names.

My desired outcome is:

let obj = [
    {
        id: [1,2],
        name: 'bob'
    },
    {
        id: 3,
        name: 'karl'
    },
        {
        id: [4,5],
        name: 'joe'
    },
    {
        id: 6,
        name: 'rick'
    },
];

Can anyone help?

Juliette
  • 4,309
  • 2
  • 14
  • 31
  • Do the non grouped ids need to appear standalone (ie. not in an array)? If they can also be in an array, then this question will answer your question: [Group array items using object](https://stackoverflow.com/q/31688459) – Nick Parsons May 16 '21 at 01:31

2 Answers2

2

You can easily achieve this result using reduce and find. If the existing element is an array then you need to push it into array else create an array and push the existing element in the array along with new id

let obj = [
  {
    id: 1,
    name: "bob",
  },
  {
    id: 2,
    name: "bob",
  },
  {
    id: 3,
    name: "karl",
  },
  {
    id: 4,
    name: "joe",
  },
  {
    id: 5,
    name: "joe",
  },
  {
    id: 6,
    name: "rick",
  },
];

const result = obj.reduce((acc, curr) => {
  const { id, name } = curr;
  const findEl = acc.find((o) => o.name === name);
  if (findEl) {
    if (Array.isArray(findEl.id)) {
      findEl.id.push(id);
    } else {
      findEl.id = [findEl.id, id];
    }
  } else {
    acc.push({ id, name });
  }
  return acc;
}, []);

console.log(result);

You can improve its time complexity by introducing a dictionary and no need to find elements every time in reduce. But here order can change of the object inside result

let obj = [
  {
    id: 1,
    name: "bob",
  },
  {
    id: 2,
    name: "bob",
  },
  {
    id: 3,
    name: "karl",
  },
  {
    id: 4,
    name: "joe",
  },
  {
    id: 5,
    name: "joe",
  },
  {
    id: 6,
    name: "rick",
  },
];

const dict = {};
obj.forEach((obj) => {
  const { id, name } = obj;
  if (dict[name]) {
    if (Array.isArray(dict[name])) {
      dict[name].push(id);
    } else {
      dict[name] = [dict[name], id];
    }
  } else {
    dict[name] = id;
  }
});

const result = Object.entries(dict).map(([name, id]) => ({ name, id }));

console.log(result);
DecPK
  • 24,537
  • 6
  • 26
  • 42
0

Array.prototype.reduce() is useful in this case.

let obj = [{
    id: 1,
    name: 'bob'
  },
  {
    id: 2,
    name: 'bob'
  },
  {
    id: 3,
    name: 'karl'
  },
  {
    id: 4,
    name: 'joe'
  },
  {
    id: 5,
    name: 'joe'
  }, {
    id: 6,
    name: 'rick'
  },
];
const mergeObjectByValue = (objArray) => {
  const newObjs = objArray.reduce((prev, {
    name,
    id
  }) => {
    (name in prev) ? prev[name].push(id): prev[name] = [id]
    return prev;
  }, {})
  return Object.entries(newObjs).map(([name, ids]) => ({
    name,
    id: ids.length > 1 ? ids : ids[0],
  }))
}
console.log(mergeObjectByValue(obj))
Reinis
  • 477
  • 1
  • 5
  • 13