使用JavaScript将一个包含对象的数组扁平化为另一个对象数组

6
我在多种情境和语言中都遇到过这个问题,我总是能够解决它,但我想最终找出一个正确的模式来处理它。它来自于联接SQL表。通常我会进行两次调用,一次是获取物品,一次是获取评论。但我知道有一种方法可以在一次调用中获取所有内容,然后将结果展开。
我想要做的是获取一个像这样的数组:
[
  {
    itemId: 1,
    comments: {
      commentId: 1
    }
  },
  {
    itemId: 1,
    comments: {
      commentId: 2
    }
  },
  {
    itemId: 2,
    comments: {
      commentId: 3
    }
  }
]

把它变成这样:
[
  {
    itemId: 1,
    comments: [
      {
        commentId: 1
      },
      {
        commentId: 2
      }
    ]
  },
  {
    itemId: 2,
    comments: [
      {
        commentId: 3
      }
    ]
  }
]
2个回答

1
以下内容适用于您:

function combine(arr) {
    var newObj = {};

    // combine the comments
    for (var i=0; i < arr.length; i++) {
        if (newObj[arr[i].itemId]) {
            newObj[arr[i].itemId].push(arr[i].comments);
        } else {
            newObj[arr[i].itemId] = [arr[i].comments];
        }
    }

    // make the list
    var keys = Object.keys(newObj);
    return keys.map(function(key){return {itemId: key, comments: newObj[key]} })
}

1
另外,既然您已经在使用ES5,您可能会喜欢在最后一步中使用Array#map。它稍微更易读一些;-) - John Dvorak
@JanDvorak 这会让我很失落!嘿,楼主!你的 ID 是正常的,对吧?! - Andbdrew
我们也可以使用 keys.sort() 如果我们真的想要 :) - Andbdrew
@Andbdrew,你的答案对于这个问题是正确的,但我的问题与我实际需要的不同,我在输入时弄混了,我不确定是否应该发布另一个问题或编辑此问题。基本上,我的起始数组只是一个像这样的数组:[{itemId: 1, commentId: 1}, {itemId: 1, commentId: 2}]等等。我要寻找的结果仍然是相同的。你的答案让我感觉走在了正确的轨道上,但我还没有想出来。谢谢你的帮助! - user2458067
实际上,我刚刚尝试了您更新的答案,它完全符合我的要求。再次感谢! - user2458067
显示剩余4条评论

1
您可以使用filter()函数:
function combine(src) {
    var dict = {};
    return src.filter(function(item) {
        if (!dict[item.itemId]) {
            item.comments = [ item.comments ];
            dict[item.itemId] = item;
            return true;
        } else {
            dict[item.itemId].comments.push(item.comments);
            return false;
        }
    });
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接