Juliette
Juliette

Reputation: 4439

duplicates for array of objects into organized data structure

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?

Upvotes: 0

Views: 66

Answers (2)

Reinis
Reinis

Reputation: 505

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

Upvotes: 0

DecPK
DecPK

Reputation: 25408

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

Upvotes: 2

Related Questions