Reputation: 1331
I want to convert showtimesData
to showtimesByLocationByDate
Any idea how to do it without using any third party library and just using pure javascript? Otherwise, what 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"]
}
]
},
];
Upvotes: 6
Views: 524
Reputation: 386868
This proposal features just Array.prototype.reduce()
with one temporary object for referencing the array items.
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: Generic 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>');
Upvotes: 4
Reputation: 14423
I'd propose this transformation:
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 transform it to that, I'd propose grabing this transformation and map it to 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).
Upvotes: 4