用lodash嵌套数组分组

时间:2018-12-26 09:16:08

标签: javascript

我有一个小型的Web应用程序,该应用程序使用API​​调用来获取数据,响应是一系列报告,每个报告都有唯一的ID,应用程序,类型和标题。

我想通过按应用程序分组然后按类型将其映射到新对象中 如下所述。

输入:

[
  {
    "id": "REPORT1",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT2",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT3",
    "application": "APP1",
    "type": "TYPE2",
    "title": ""
  },
  {
    "id": "REPORT4",
    "application": "APP2",
    "type": "TYPE3",
    "title": ""
  }
]

所需的输出:

{
  "APP1": {
    "TYPE1": [
      {
        "id": "REPORT1",
        "application": "APP1",
        "type": "TYPE1",
        "title": ""
      },
      {
        "id": "REPORT2",
        "application": "APP1",
        "type": "TYPE1",
        "title": ""
      }
    ],
    "TYPE2": [
      {
        "id": "REPORT3",
        "application": "APP1",
        "type": "TYPE2",
        "title": ""
      }
    ]
  },
  "APP2": {
    "TYPE3": [
      {
        "id": "REPORT4",
        "application": "APP2",
        "type": "TYPE3",
        "title": ""
      }
    ]
  }
}

有了loadash,我想到了这一点:

const output = _(input)
  .groupBy(report => report.application)
  .value()

application分组后,我需要按type进行另一个嵌套分组或映射,但是卡住了。

4 个答案:

答案 0 :(得分:5)

这很容易实现,无需通过the Array#reduce() function进行破折号。

有关如何实现此目的的详细信息,请参见代码段源代码中的注释:

var input = [{
    "id": "REPORT1",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT2",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT3",
    "application": "APP1",
    "type": "TYPE2",
    "title": ""
  },
  {
    "id": "REPORT4",
    "application": "APP2",
    "type": "TYPE3",
    "title": ""
  }
];

var output = input.reduce((result, item) => {

  // Get app object corresponding to current item from result (or insert if not present)
  var app = result[item.application] = result[item.application] || {};

  // Get type array corresponding to current item from app object (or insert if not present)
  var type = app[item.type] = app[item.type] || [];

  // Add current item to current type array
  type.push(item);

  // Return the result object for this iteration
  return result;

}, {});

console.log(output);
.as-console-wrapper {
height:100% !important;
max-height:unset !important;
}

答案 1 :(得分:2)

您可以采用动态方法对想要的键进行分组。

groups = ["application", "type"]

然后减少数据数组和键数组,并根据需要构建新对象,或者与最后一组一起构建用于推送实际对象的数组。

如有必要,可以轻松地将此解决方案扩展到更多的嵌套组。

var data = [{ id: "REPORT1", application: "APP1", type: "TYPE1", title: "" }, { id: "REPORT2", application: "APP1", type: "TYPE1", title: "" }, { id: "REPORT3", application: "APP1", type: "TYPE2", title: "" }, { id: "REPORT4", application: "APP2", type: "TYPE3", title: "" }],
    groups = ["application", "type"],
    grouped = data.reduce((r, o) => {
        groups
            .reduce((group, key, i, { length }) =>
                group[o[key]] = group[o[key]] || (i + 1 === length ? [] : {}), r)
            .push(o);

        return r;
    }, {});
    
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 2 :(得分:2)

es6,对象的扩散和缩小使其变得更加简单

const input = [
  {
    "id": "REPORT1",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT2",
    "application": "APP1",
    "type": "TYPE1",
    "title": ""
  },
  {
    "id": "REPORT3",
    "application": "APP1",
    "type": "TYPE2",
    "title": ""
  },
  {
    "id": "REPORT4",
    "application": "APP2",
    "type": "TYPE3",
    "title": ""
  }
]


const output = input.reduce((acc, item) => ({
  ...acc,
  [item.application]: {
    ...acc[item.application],
    [item.type]: [
      ...(acc[item.application] && acc[item.application][item.type] || []),
      item,
    ]
  }
}), {})

console.log(output)

答案 3 :(得分:0)

我个人发现在 Lodash 中结合 _.groupBy 和 _.mapValues 时这更易读:

var input = [{ id: "REPORT1", application: "APP1", type: "TYPE1", title: "" }, { id: "REPORT2", application: "APP1", type: "TYPE1", title: "" }, { id: "REPORT3", application: "APP1", type: "TYPE2", title: "" }, { id: "REPORT4", application: "APP2", type: "TYPE3", title: "" }]

const output = _.mapValues(_.groupBy(input, i => i.application),app => _.groupBy(app, i => i.type))

console.log(output)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>