Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping array of objects by multiple keys

I feel embarrassed for asking this question as I should know how to figure it out, but I'm spinning my wheels on grouping an array of objects by multiple keys.

Here's the data:

[
      {
        "car": "audi",
        "type": "A6",
        "style": "Avant",
        "year": "1996"
      },
      {

        "car": "audi",
        "type": "A4",
        "style": "2",
        "year": "2006"
      },
      {

        "car": "audi",
        "type": "A4",
        "style": "L W12",
        "year": "2006"
      },
      {

        "car": "audi",
        "type": "80",
        "style": "GLE",
        "year": "1975"
      },
      {

        "car": "audi",
        "type": "A6",
        "style": "Avant L",
        "year": "1996"
      },
      {
        "car": "audi",
        "type": "A6",
        "style": "3.2 Multitronic",
        "year": "2006"
      },
]

What I've been trying to generate with little success is the following:

 [{
   "audi": [{
     "1996": {
       "A6": ["Avant, Avant L"]
     }
   }, {
     "2006": }
       "A6": ["3.2 Multitronic"],
       "A4": ["L W12", "2"]
     }
   }
   ....
 }]

The schema is:

{
    "car1": [{
        "year1": {
            "style1": ["trim1", "trim2"],
            "style2": ["trim1", "trim2"]
        },
        "year1": {
            "style1": ["trim1", "trim2"],
            "style2": ["trim1", "trim2"]
        }
    }],
    "car2": [{
        "year1": {
            "style1": ["trim1", "trim2"],
            "style2": ["trim1", "trim2"]
        },
        "year2": {
            "style1": ["trim1", "trim2"],
            "style2": ["trim1", "trim2"]
        }
    }]
}

I've tried the following with lodash

  let result = _.chain(carData)
    .groupBy('car')
    .toPairs()
    .map(function(curr) {
        return _.zipObject(['car', 'year'], curr);
    })
    .value();

This gets me part of the way, but I end up with incomplete data when it comes to the styles and types for each year of the car.

like image 244
hybrid9 Avatar asked Mar 23 '26 20:03

hybrid9


2 Answers

You could use a hash object and a nested approach for the given properties.

var data = [{ car: "audi", type: "A6", style: "Avant", year: 1996 }, { car: "audi", type: "A4", style: 2, year: 2006 }, { car: "audi", type: "A4", style: "L W12", year: 2006 }, { car: "audi", type: 80, style: "GLE", year: 1975 }, { car: "audi", type: "A6", style: "Avant L", year: 1996 }, { car: "audi", type: "A6", style: "3.2 Multitronic", year: 2006 }],
    keys = ['car', 'year', 'type'],
    result = [];

data.forEach(function (a) {
    keys.reduce(function (r, k) {
        var o = {};
        if (!r[a[k]]) {
            r[a[k]] = { _: [] };
            o[a[k]] = r[a[k]]._;
            r._.push(o);
        }
        return r[a[k]];
    }, this)._.push(a.style);
}, { _: result });
   
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
like image 55
Nina Scholz Avatar answered Mar 26 '26 08:03

Nina Scholz


Here's a (slightly verbose) solution that generates exactly the JSON object shape you wanted and groups by unlimited keys:

var cars = [{
  "car": "audi",
  "type": "A6",
  "style": "Avant",
  "year": "1996"
}, {

  "car": "audi",
  "type": "A4",
  "style": "2",
  "year": "2006"
}, {

  "car": "audi",
  "type": "A4",
  "style": "L W12",
  "year": "2006"
}, {

  "car": "audi",
  "type": "80",
  "style": "GLE",
  "year": "1975"
}, {

  "car": "audi",
  "type": "A6",
  "style": "Avant L",
  "year": "1996"
}, {
  "car": "audi",
  "type": "A6",
  "style": "3.2 Multitronic",
  "year": "2006"
}, ];

function groupBy(list, prop) {
  return list.reduce((groupped, item) => {
    var key = item[prop];
    delete item[prop];
    if (groupped.hasOwnProperty(key)) {
      groupped[key].push(item);
    } else {
      groupped[key] = [item];
    }
    return groupped
  }, {});
}

function groupSubKeys(obj, properties, propIndex) {
  var grouppedObj = groupBy(obj, properties[propIndex]);
  Object.keys(grouppedObj).forEach((key) => {
    if (propIndex < properties.length - 2) {
      grouppedObj[key] = groupSubKeys(grouppedObj[key], properties, propIndex + 1);
    } else {
      grouppedObj[key] = grouppedObj[key].map(item => item[properties[propIndex + 1]])
    }
  });
  return grouppedObj;
}

function groupByProperties(list, properties) {
  return groupSubKeys(list, properties, 0);
}

console.log(groupByProperties(cars, ['car', 'year', 'type', 'style']));

Here's a running example: http://codepen.io/rarmatei/pen/evmBOo

like image 32
Rares Matei Avatar answered Mar 26 '26 09:03

Rares Matei



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!