简体   繁体   English

lodash通过多个键将数组分组

[英]lodash grouping an array by multiple keys

[Update]: I've removed most of the layout and lodash (failed code) from before because the JSON data format has changed. [更新]:由于JSON数据格式已更改,因此我从之前删除了大多数布局和lodash(失败的代码)。

I'm trying to group a data set in preparation for aggregating totals. 我正在尝试对数据集进行分组,以准备总计。 Here is the incoming JSON layout. 这是传入的JSON布局。 I need to group by country, then by brand: 我需要按国家/地区分组,然后按品牌分组:

  [
    {
      $id: "1",
      countryCode: "HT",
      brand: "CO",
      roomNights: 12,
      hotelSpend: 2000
     },
    {
     $id: "2",
     countryCode: "PK",
     brand: "HH",
     roomNights: 201,
     hotelSpend: 10000
    },
   {
     $id: "3",
     countryCode: "RO",
     brand: "CO",
     roomNights: 34,
     hotelSpend: 5000
    },
   { 
     $id: "4",
     countryCode: "US",
     brand: "ES",
     roomNights: 120,
     hotelSpend: 56000
   },
   {
     $id: "5",
     countryCode: "PK",
     brand: "HH",
     roomNights: 145,
     hotelSpend: 33000
   }
  ]

The data needs to be transformed into this format: 数据需要转换为以下格式:

        ['Brand','HT'     , 'PK'        , 'US'     , 'RO', 'Avg Rm', 'Avg Spend']
        ['HH'   ,'0/0'    ,'201/10000', '0/0'       , '0/0'     , 201,   10000],
        ['CO'   ,'12/2000','0/0',     , '0/0'       , '34/5000', 23 ,    3500],
        ['ES'   , '0/0'    ,'0/0'    , '120/50000'  , '0/0'    , 120, 50000]

The roomNights and hotelSpend will be totalled per brand & country and the average of each will need to be calculated fields at the end. 每个品牌和国家/地区的roomNights和hotelSpend总计,最后需要计算每个字段的平均值。

Thanks! 谢谢!

Let's first define a mean function and add it to _ : 首先定义一个mean函数并将其添加到_

_.mixin({
  mean: function(ds) {
    return _(ds).foldr(function(a, b) { return a + b; }, 0) / ds.length;
  }
}); 

Let's define functions for selecting the rows and columns: 让我们定义用于选择行和列的函数:

var row = function(d) { return d.brand; };
var col = function(d) { return d.countryCode; };

aggr function takes a sub-list of our data and aggregates its values into one value (which here is a string representation of a rational number): aggr函数获取数据的子列表并将其值聚合为一个值(这里是有理数的字符串表示形式):

var aggr = function(ds) {
  var val = _(ds).foldr(function(a, b) {
    return {
      roomNights: a.roomNights + b.roomNights,
      hotelSpend: a.hotelSpend + b.hotelSpend
    };
  }, {roomNights: 0, hotelSpend: 0});

  return val.roomNights + "/" + val.hotelSpend;
};

Our rows and columns labels: 我们的行和列标签:

rows = _.chain(data).map(row).unique().value();
columns = _.chain(data).map(col).unique().value();

The pivot: 枢纽:

[["Brand/Country"].concat(columns).concat(["Avg Rm", "Avg Spend"])] // header row
.concat(_(rows).map(function(r){

  // data in this row
  rdata = _(data).filter(function(d) { return row(d) == r; });

  return [r].concat(_(columns).map(function(c){
    return aggr(_(rdata).filter(function(d) {return col(d) == c; }));
  }))
  // the last two columns in each row
  .concat([
    _.chain(rdata).map(function(d) { return d.roomNights; }).mean().value(),
    _.chain(rdata).map(function(d) { return d.hotelSpend; }).mean().value()
  ]);
}));

You can control the order or filter the result by specific countryCode or brand by modifying the rows and columns arrays, similar to spreadsheets. 您可以通过修改rowscolumns数组(类似于电子表格)来控制订单或通过特定的countryCodebrand过滤结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM