如何根据 属性 值对数组进行分组?

How do I group an array based on a property value?

我有两个 JavScript objects (POJO):

var first_original = [
  {group: "A", title: "foo1"},
  {group: "A", title: "foo2"},
  {group: "A", title: "foo3"},
  {group: "A", title: "foo4"},
  {group: "B", title: "foo5"},
  {group: "B", title: "foo6"},
  {group: "B", title: "foo7"}
];
var second_original = [
  {group: null, title: "bar1"},
  {group: null, title: "bar2"},
  {group: null, title: "bar3"},
  {group: null, title: "bar4"},
  {group: null, title: "bar5"},
  {group: null, title: "bar6"},
  {group: null, title: "bar7"}
];

我很难概念化如何将它们映射到以下结构:

var first_copy = [
  {
    header: "A",
    items: [
      {group: "A", title: "foo1"},
      {group: "A", title: "foo2"},
      {group: "A", title: "foo3"},
      {group: "A", title: "foo4"}
    ]
  },
  {
    header: "B",
    items: [
      {group: "B", title: "foo5"},
      {group: "B", title: "foo6"},
      {group: "B", title: "foo7"}
    ]
  }
];
var second_copy = [
  {
    header: null,
    items: [
      {group: null, title: "bar1"},
      {group: null, title: "bar2"},
      {group: null, title: "bar3"},
      {group: null, title: "bar4"},
      {group: null, title: "bar5"},
      {group: null, title: "bar6"},
      {group: null, title: "bar7"}
    ]
  }
];

我尝试使用 .forEach():

function getRemappedObject(contentList) {
  val lastGroup    = null;
  var currentIndex = 0;
  var groups       = [];
  contentList.forEach(function(item) {
    if (!groups[currentIndex]) {
      groups.push({items: [item]});
    } else {
      groups[currentIndex].items.push(item);
    }
    groups[currentIndex].header = item.group;
    if (item.group && item.group !== lastGroup) {
      lastGroup = item.group;
      currentIndex++;
    }
  });
  return groups;
}

但这在规范的 header 部分惨遭失败。我认为这是睡眠不足,但我很好奇是否有更好的方法。我想在没有 Underscore 或 Lodash 的情况下解决它。请使用 ECMAScript 5 或 6。

如何将上述结构映射到预期输出?

使用另一个 Array 来跟踪 header 值;

function organise(arr) {
    var headers = [], // an Array to let us lookup indicies by group
        objs = [],    // the Object we want to create
        i, j;
    for (i = 0; i < arr.length; ++i) {
        j = headers.indexOf(arr[i].group); // lookup
        if (j === -1) { // this entry does not exist yet, init
            j = headers.length;
            headers[j] = arr[i].group;
            objs[j] = {};
            objs[j].header = arr[i].group;
            objs[j].items = [];
        }
        objs[j].items.push( // create clone
            {group: arr[i].group, title: arr[i].title}
        );
    }
    return objs;
}

var first_copy = organise(first_original);

如果您可以假设分组将始终是 string 即永远不会 null 您可以通过键而不是 indexOf 查找更有效地完成它


ES6 可能会让你更像这里的其他解决方案一样通过例如a MapWeakMap 不允许基元作为键)