0

I am trying to iterate over an array that's similar to the below structure, and for each object that has the same id, I want them combined into a single object but with an array of all the 'names' associated with that id. My Array is pre-sorted by id and I can't use JQuery, only vanilla JS.

Convert this:

var array = [
   {id=1, name = "Orange"},
   {id=1, name = "Blue"},
   {id=1, name = "Green"},
   {id=2, name = "Blue"},
   {id=3, name = "Orange"},
   {id=3, name = "Blue"}
]

To this:

var newArray = [
   {id=1, nameList = [Orange, Blue, Green]},
   {id=2, nameList = [Blue]},
   {id=3, namelist = [Orange, Blue]}
]

I was trying to do something like this by comparing the first object to the next object in the array, then setting the first object to the second object, but got stuck because 'secondObject' wasn't actually the next object in the array.

for (var i in array) {
   firstObject = array[i];
   secondObject = array[i + 1];
   if (firstObject.id === secondObject.id) {
      firstObject['nameList'] = [firstObject.name + ',' + secondObject.name]

    } else {
    continue;
    }
  firstObject = secondObject;


}

I have to do this with a couple thousand id's, and most of the id's are repeated with different names, but there are a few single id objects like id 2.

MattMcCode
  • 187
  • 4
  • 18

3 Answers3

3

An alternative is using the function reduce

var array = [   {id:1, name : "Orange"},   {id:1, name : "Blue"},   {id:1, name : "Green"},   {id:2, name : "Blue"},   {id:3, name : "Orange"},   {id:3, name : "Blue"}]

var result = Object.values(array.reduce((a, c) => {
  (a[c.id] || (a[c.id] = {id: c.id, nameList: []})).nameList.push(c.name);
  return a;
}, {}));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ele
  • 33,468
  • 7
  • 37
  • 75
  • nice but can you explin your code, i love to know how come nameList appears to have .push when it was not declared, and what does the () do with a[c.id] OR(||) ...so on – optimus Apr 16 '22 at 18:22
1

Because of the sorted items, you could check the last item in the result array and if different from the actual item generate a new result object. Later push name.

var array = [{ id: 1, name: "Orange" }, { id: 1, name: "Blue" }, { id: 1, name: "Green" }, { id: 2, name: "Blue" }, { id: 3, name: "Orange" }, { id: 3, name: "Blue" }],
    grouped = array.reduce(function (r, { id, name }) {
        if (!r.length || r[r.length - 1].id !== id) {
            r.push({ id, namelist: [] });
        }
        r[r.length - 1].namelist.push(name);
        return r;
    }, []);

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

If you don't have to do it in-place, you can just create another object and put things into that directly.

var map = {}
for (var obj in array) {
  var id = obj.id;
  var name = obj.name;
  if (!map[id]) {
    map[id] = [];
  }
  map[id].push(name); 
}

Then iterate across the map to build up your result:

var result = [];
Object.keys(map).forEach(function(key) {
  result.push[key, map[key]];
}
fennel
  • 371
  • 2
  • 11