Home > other >  Group Array of Object by multiple keys
Group Array of Object by multiple keys

Time:07-06

I'm newbie in programming, so i need some help. I have array of objects. I need to sort it and turn it into an array of objects, which will contain the key city, then an array of objects from the leaders, and an array of coffee shops.

  let arr = [
    {city: 'New York', boss: 'John', name: 'Caffe 1'},
    {city: 'New York', boss: 'John', name: 'Caffe 2'},
    {city: 'New York', boss: 'Ben', name: 'Caffe 3'},
    {city: 'New York', boss: 'Ben', name: 'Caffe 4'},
    {city: 'Washington', boss: 'Lisa', name: 'Caffe 5'},
    {city: 'Washington', boss: 'Lisa', name: 'Caffe 6'},
    {city: 'Washington', boss: 'Kate', name: 'Caffe 7'},
    {city: 'Washington', boss: 'Kate', name: 'Caffe 8'},
    {city: 'Los Angeles', boss: 'Joe', name: 'Caffe 9'}

  ]

I need to get something like this.

    let result =  [
      {city: 'New York', 
      boss:[
        {
          name: 'John', 
          caffes:[
            {name: 'Caffe 1'},
            {name: 'Caffe 2'}
                  ]
                },
        {name: 'Ben', 
          caffes: [
            {name: 'Caffe 3'},
            {name: 'Caffe 4'}
                  ]
                }     
            ]
      },
      {city: 'Washington', 
      boss:[
        {
          name: 'Lisa', 
          caffes:[
            {name: 'Caffe 5'},
            {name: 'Caffe 6'}
                  ]
                },
        {name: 'Kate', 
          caffes: [
            {name: 'Caffe 7'},
            {name: 'Caffe 8'}
                  ]
                }     
            ]
      },
      {city: 'Los Angeles', 
      boss:[
        {
          name: 'Joe', 
          caffes:[
            {name: 'Caffe 9'},
                  ]
                },
            ]
      },
      ]

The best what i can do is this:

    function sortData(data) {
    let groups = []; 

    for (let element of data) {
        let existingGroups = groups.filter((group) => group.city == element.city); 
        if (existingGroups.length > 0) {
            existingGroups[0].city = element.city;
            existingGroups[0].boss =  element.boss;

        } else {
            let newGroup = {
                city: element.city,
        boss: element.boss

            };
            groups.push(newGroup); 
        }
    }
    return groups; 
}

And its makes the:

[ { city: 'New York', boss: 'Ben' },
  { city: 'Washington', boss: 'Kate' },
  { city: 'Los Angeles', boss: 'Joe' } ]

But i dont know how to make it more complex.

I trying many ways, but any of them can't help me. How can i do this?

CodePudding user response:

It's true that this is at its heart a very straight forward 'group by' as in this duplicate How can I group an array of objects by key?. But your data requires another level of grouping by boss within the first grouping by city.

Here's an example grouping into an object, iterating each element in a for...of loop then retrieving or creating the relevant properties using logical nullish assignment (??=). This is done first for the city and then again for the city.boss. Finally the we take the Object.values() of the grouped object as the result, and map over it in order to also convert each boss object to a an array of values.

let arr = [{ city: 'New York', boss: 'John', name: 'Caffe 1' }, { city: 'New York', boss: 'John', name: 'Caffe 2' }, { city: 'New York', boss: 'Ben', name: 'Caffe 3' }, { city: 'New York', boss: 'Ben', name: 'Caffe 4' }, { city: 'Washington', boss: 'Lisa', name: 'Caffe 5' }, { city: 'Washington', boss: 'Lisa', name: 'Caffe 6' }, { city: 'Washington', boss: 'Kate', name: 'Caffe 7' }, { city: 'Washington', boss: 'Kate', name: 'Caffe 8' }, { city: 'Los Angeles', boss: 'Joe', name: 'Caffe 9' }]

const groupedByCity = {};

for (const { city, boss, name } of arr) {
  const cityGroup = (groupedByCity[city] ??= { city, boss: {} });
  const bossGroup = (cityGroup.boss[boss] ??= { name: boss, caffes: [] });

  bossGroup.caffes.push({ name })
}

const result = Object.values(groupedByCity)
  .map(o => ({ ...o, boss: Object.values(o.boss) }));

console.log(result)

  • Related