How to group an array of javascript objects by several of its properties?

I want to convert showtimesData to showtimesByLocationByDate

Any idea how to do this without using a third-party library and just using pure javascript? Otherwise, which third-party library can I use for this?

  var showtimesData = [ {"location":"location1", "date":"31-12-2016", "time":"1:00"}, {"location":"location1", "date":"31-12-2016", "time":"2:00"}, {"location":"location1", "date":"01-01-2017", "time":"3:00"}, {"location":"location1", "date":"01-01-2017", "time":"4:00"}, {"location":"location2", "date":"31-12-2016", "time":"1:00"}, {"location":"location2", "date":"31-12-2016", "time":"2:00"}, {"location":"location2", "date":"01-01-2017", "time":"3:00"}, {"location":"location2", "date":"01-01-2017", "time":"4:00"}, ]; var showtimesByLocationByDate = [ { "location":"location1", "dates":[ { "date":"31-12-2016", "times":["1:00","2:00"] }, { "date":"01-01-2017", "times":["3:00","4:00"] } ] }, { "location":"location2", "dates":[ { "date":"31-12-2016", "times":["1:00","2:00"] }, { "date":"01-01-2017", "times":["3:00","4:00"] } ] }, ]; 
+6
source share
2 answers

In this sentence, there is only Array.prototype.reduce() with one temporary object to reference the elements of the array.

 var showtimesData = [{ "location": "location1", "date": "31-12-2016", "time": "1:00" }, { "location": "location1", "date": "31-12-2016", "time": "2:00" }, { "location": "location1", "date": "01-01-2017", "time": "3:00" }, { "location": "location1", "date": "01-01-2017", "time": "4:00" }, { "location": "location2", "date": "31-12-2016", "time": "1:00" }, { "location": "location2", "date": "31-12-2016", "time": "2:00" }, { "location": "location2", "date": "01-01-2017", "time": "3:00" }, { "location": "location2", "date": "01-01-2017", "time": "4:00" }, ], showtimesByLocationByDate = showtimesData.reduce(function (r, a) { var o; if (!(a.location in r.obj)) { o = { location: a.location, dates: [] }; r.obj[a.location] = { dates: o.dates }; r.array.push(o); } if (!(a.date in r.obj[a.location])) { o = { date: a.date, times: [] }; r.obj[a.location].dates.push(o); r.obj[a.location][a.date] = o.times; } r.obj[a.location][a.date].push(a.time); return r; }, { array: [], obj: {} }).array; document.write('<pre>' + JSON.stringify(showtimesByLocationByDate, 0, 4) + '</pre>'); 

Bonus: general version with a given data structure

 var showtimesData = [{ "location": "location1", "date": "31-12-2016", "time": "1:00" }, { "location": "location1", "date": "31-12-2016", "time": "2:00" }, { "location": "location1", "date": "01-01-2017", "time": "3:00" }, { "location": "location1", "date": "01-01-2017", "time": "4:00" }, { "location": "location2", "date": "31-12-2016", "time": "1:00" }, { "location": "location2", "date": "31-12-2016", "time": "2:00" }, { "location": "location2", "date": "01-01-2017", "time": "3:00" }, { "location": "location2", "date": "01-01-2017", "time": "4:00" }, ], structure = [ { key: 'location', data: 'dates' }, { key: 'date', data: 'times' }, { key: 'time' } ], showtimesByLocationByDate = showtimesData.reduce(function (r, a) { var properties = structure.slice(), lastKey = properties.pop().key; properties.reduce(function (rr, b) { var o = {}, p = {}, key = b.key, value = a[key], array = b.data; if (!(value in rr.obj)) { o[key] = value; o[array] = []; p[array] = o[array]; rr.obj[value] = p; rr.array.push(o); } return { array: rr.obj[value][array], obj: rr.obj[value] }; }, r).array.push(a[lastKey]); return r; }, { array: [], obj: {} }).array; document.write('<pre>' + JSON.stringify(showtimesByLocationByDate, 0, 4) + '</pre>'); 
+4
source

I would suggest the following conversion:

 var showtimesData = [ {"location":"location1", "date":"31-12-2016", "time":"1:00"}, {"location":"location1", "date":"31-12-2016", "time":"2:00"}, {"location":"location1", "date":"01-01-2017", "time":"3:00"}, {"location":"location1", "date":"01-01-2017", "time":"4:00"}, {"location":"location2", "date":"31-12-2016", "time":"1:00"}, {"location":"location2", "date":"31-12-2016", "time":"2:00"}, {"location":"location2", "date":"01-01-2017", "time":"3:00"}, {"location":"location2", "date":"01-01-2017", "time":"4:00"}, ]; var transformed = showtimesData.reduce(function(obj, show){ //var { location, date, time } = show; //if destructuring is available var location = show.location, date = show.date, time = show.time, objLocation = obj[location] = obj[location] || { dates : { } }, dates = objLocation.dates, date = dates[date] = dates[date] || [ ]; date.push(time); return obj; }, {}); results.innerHTML = JSON.stringify(transformed, null, '\t'); 
 <pre id="results"></pre> 

But if you really want to convert it to this, I would suggest grabbing that conversion and matching it with your proposed structure.

 var showtimesData = [ {"location":"location1", "date":"31-12-2016", "time":"1:00"}, {"location":"location1", "date":"31-12-2016", "time":"2:00"}, {"location":"location1", "date":"01-01-2017", "time":"3:00"}, {"location":"location1", "date":"01-01-2017", "time":"4:00"}, {"location":"location2", "date":"31-12-2016", "time":"1:00"}, {"location":"location2", "date":"31-12-2016", "time":"2:00"}, {"location":"location2", "date":"01-01-2017", "time":"3:00"}, {"location":"location2", "date":"01-01-2017", "time":"4:00"}, ]; var transformed = showtimesData.reduce(function(obj, show){ //var { location, date, time } = show; //if destructuring is available var location = show.location, date = show.date, time = show.time, objLocation = obj[location] = obj[location] || { dates : { } }, dates = objLocation.dates, date = dates[date] = dates[date] || [ ]; date.push(time); return obj; }, {}); var secondTransformed = Object.keys(transformed).map(function(key){ var dates = transformed[key].dates, transformedDates = Object.keys(dates).map(function(key){ return { date : key, times : dates[key] } }); return { location : key, dates : transformedDates } }); results.innerHTML = JSON.stringify(secondTransformed, null, '\t'); 
 <pre id="results"></pre> 

Although there are better ways to do this (performance wise).

+4
source

All Articles