【问题标题】:How to group a javascript object array by multiple of its properties?如何通过多个属性对 javascript 对象数组进行分组?
【发布时间】:2016-04-30 21:40:48
【问题描述】:

我想将showtimesData 转换为showtimesByLocationByDate

知道如何在不使用任何第三方库且仅使用纯 JavaScript 的情况下做到这一点吗?否则,我可以使用什么第三方库?

    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"]
                }
            ]
        },
    ];

【问题讨论】:

  • 是否必须遵循特定格式?如果它是对象的属性,日期查找会快得多。
  • 如果我要将日期设置为属性,是否可以循环访问属性以获取字符串形式的日期?
  • 是的,可以循环遍历对象的属性。
  • 我做了一些谷歌搜索,是使用 Object.keys 函数吗?

标签: javascript arrays json grouping


【解决方案1】:

此提案仅包含 Array.prototype.reduce() 和一个用于引用数组项的临时对象。

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

奖励:具有给定数据结构的通用版本

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

【讨论】:

  • 你的回答很准确,但我只是想知道有没有办法让它更通用?
  • @Rajesh,这取决于数据结构及其通用性。
  • 我只是想知道我们是否可以创建一个函数,将数据和属性传递给分组依据,并返回一个分组值。以下是我尝试过的JSFiddle
【解决方案2】:

我建议这种转变:

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');
&lt;pre id="results"&gt;&lt;/pre&gt;

但如果你真的想把它转换成那样,我建议抓住这个转换并将它映射到你提议的结构。

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');
&lt;pre id="results"&gt;&lt;/pre&gt;

虽然有更好的方法来做到这一点(性能方面)。

【讨论】:

  • 记录Uncaught SyntaxError: Unexpected token { console
  • 这是解构赋值,你的浏览器还不支持。
  • 好的,换个浏览器试试
  • @guest271314,不用担心我改了,所以现在不用了。
  • fwiw,在 chromium 49 处返回预期结果。也可以在 Answer 中包含解构版本吗?
猜你喜欢
  • 1970-01-01
  • 2021-01-13
  • 2020-07-25
  • 2011-07-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
相关资源
最近更新 更多