6

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"]
                }
            ]
        },
    ];
4
  • Does it have to follow that specific format? Date lookup would be much faster if it'd be a property of an object. Commented Jan 24, 2016 at 16:14
  • if I were to set the dates as properties, can I loop through the properties to get the dates as strings? Commented Jan 24, 2016 at 16:23
  • Yes, it's possible to loop through the properties of the object. Commented Jan 24, 2016 at 16:32
  • I did some googling, is it using Object.keys function? Commented Jan 24, 2016 at 16:40

2 Answers 2

4

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).

Sign up to request clarification or add additional context in comments.

9 Comments

Logs Uncaught SyntaxError: Unexpected token { at console
It's the destructuring assignment, your browser doesn't support that yet.
Ok, will try at different browser
@guest271314, no worries I change it so it doesn't use it now.
fwiw, returns expected results at chromium 49 . Can include destructuring version at Answer as well ?
|
4

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>');

3 Comments

You answer is very precise, but I was just wondering is there a way to make it more generic?
@Rajesh, it depends on the data structure and how generic it should be.
I was just wondering if we could make a function where we pass data and property to group by, and it returns a grouped value. Following is the JSFiddle that I have tries yet.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.