1

I need an efficient way to loop through an array of object literals and concatenate values within the objects that have duplicate IDs.

Is there a more elegant way of doing this versus having multiple for loops nested within each other?

For example, this is the data I am given:

{ "theList": [
    {
        "id": 101,
        "name": "Bubbles' Cat Farm",
        "number": "123"
    },
    {
        "id": 102,
        "name": "Sunnyvale Park",
        "number": "456"
    },
    {
        "id": 101,
        "name": "Bubbles' Cat Farm",
        "number": "789"
]};

The expected result should be:

{ "theList": [
    {
        "id": 101,
        "name": "Bubbles' Cat Farm",
        "number": "123, 789"
    }, 
    {
        "id": 102,
        "name": "Sunnyvale Park",
        "number": "456"
]}


zaoies
  • 11
  • 1
  • unless that the data structure is not always id, name, number you should be fine with just 1 loop. – ivan Feb 01 '19 at 19:04

4 Answers4

3

You can use reduce

let obj = [{ "id": 101,"name": "Bubbles' Cat Farm","number": "123"},{"id": 102,"name": "Sunnyvale Park","number": "456"},{"id": 101,"name": "Bubbles' Cat Farm","number": "789"}];

let op = obj.reduce((out,inp)=>{
  if(out[inp.id]){
    out[inp.id].number += ', ' + inp.number;
  } else {
    out[inp.id] = inp
  }
  return out
},{})

console.log(Object.values(op))
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
2

If number is the only key which has distinct values, then you could do something like this using reduce:

const input = {"theList":[{"id":101,"name":"Bubbles' Cat Farm","number":"123"},{"id":102,"name":"Sunnyvale Park","number":"456"},{"id":101,"name":"Bubbles' Cat Farm","number":"789"}]}

const merged = input.theList.reduce((acc, {id,name,number}) =>{
  acc[id] 
    ? acc[id]["number"] += ", " + number 
    : acc[id] = {id,name,number};
    
  return acc
},{})

const final = { "theList": Object.values(merged) }
console.log(final)

Create an accumulator with each unique id as key and the object you need in the final array as value like this. Then concatenate the number when a id already exists in the accumulator, else add a new key to the accumulator.

{
  "101": {
    "id": 101,
    "name": "Bubbles' Cat Farm",
    "number": "123, 789"
  }
}

Then use Object.values to get only the values of theList in an array.

adiga
  • 34,372
  • 9
  • 61
  • 83
2

using reduce and the findIndex function you will be able to achieve what you want.

const array = [{
    "id": 101,
    "name": "Bubbles' Cat Farm",
    "number": "123"
  },
  {
    "id": 102,
    "name": "Sunnyvale Park",
    "number": "456"
  },
  {
    "id": 101,
    "name": "Bubbles' Cat Farm",
    "number": "789"
  }
]

const result = array.reduce((accum, cv) => {
  const index = accum.findIndex(item => item.id === cv.id);
  if (index === -1) {
    accum.push(cv);
  } else {
    accum[index].number += ", " + cv.number;
  }
  return accum;
}, [])

console.log(result)
Prince Hernandez
  • 3,623
  • 1
  • 10
  • 19
1

You can make your container a dictionary where the key is the ID and eachvalue is an empty list. So when you loop through the original data. If the key doesnt exist, create a list with one item. If the key does exist already, just append the value to the list.