MattMcCode
MattMcCode

Reputation: 307

Loop Over Array of Objects and Combine them if they have similar keys

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.

Upvotes: 0

Views: 2633

Answers (3)

Nina Scholz
Nina Scholz

Reputation: 386654

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

Upvotes: 1

fennel
fennel

Reputation: 391

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

Upvotes: 0

Ele
Ele

Reputation: 33726

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

Upvotes: 3

Related Questions