合并具有相同键值的JavaScript对象数组

3

我一直在尝试将具有相同id值的数组对象进行组合。我手头的数组如下:

[
{"id" : "abcd","val1" : 1,"val2": 1, "val3" : 0},
{"id" : "abcd","val1" : 1,"val2": 1, "val3" : 1},
{"id" : "efgh","val1" : 0,"val2": 0, "val3" : 1}
]

我一直在尝试找到一种方法,将它们合并以便结果如下:

[
{"id" : "abcd","val1" : 2,"val2": 2, "val3" : 1},
{"id" : "efgh","val1" : 0,"val2": 0, "val3" : 1}
]

有没有用 underscore.js 实现这个的方法?

3
你有尝试过什么吗?你在哪里遇到了困难? - Denys Séguret
@Bergi 你可能应该在这里写一个具体的下划线答案,对吧?或者你认为这个问题应该被视为重复的吗? - Denys Séguret
@dystroy:我在处理中 :-) 但我相当有信心我之前已经做过非常类似的事情,只是我找不到重复的内容了。链接 - Bergi
4个回答

4
这应该可以使用underscore的函数式方法来实现:
_.map(_.groupBy(arr, "id"), function(vals, id) {
    return _.reduce(vals, function(m, o) {
        for (var p in o)
            if (p != "id")
                m[p] = (m[p]||0)+o[p];
        return m;
    }, {id: id});
});

+1 但我有点失望,因为_并没有使它比基本解决方案更简单或更短。 - Denys Séguret
嗯,我很想为这个写一个通用的辅助函数 :-) - Bergi
嗨,这个解决方案完美地解决了我的问题。我尝试了各种下划线技巧,但是我就是无法理解那个组合的东西。现在它似乎更清晰了:)谢谢! - jiihoo

2

Refer the below example

var array = [{
    "sequence" : 1,
    "locationId" : "332228",
    "lat" : 25.246511,
    "lng" : 55.293837,
    "stopName" : "332228",
    "locationType" : "service",
    "serviceType" : "Delivery",
    "arrivalTime" : 37666,
    "departureTime" : 37830,
    "travelTime" : 1593,
    "travelDistance" : 20985,
    "travelCost" : 0,
    "serviceTime" : 30,
    "serviceTimeCost" : 0,
    "tripNumber" : 0,
    "orders" : [ 
        {
            "orderId" : "AQ137O1701240",
            "SIZE1" : "28",
            "SIZE2" : "520",
            "SIZE3" : "52"
        }
    ],
    "stopId" : "SkhirG2ioZ"
}, 
{
    "sequence" : 2,
    "locationId" : "332228",
    "lat" : 25.236407,
    "lng" : 55.272403,
    "stopName" : "332228",
    "locationType" : "service",
    "serviceType" : "Delivery",
    "arrivalTime" : 38575,
    "departureTime" : 38605,
    "travelTime" : 1593,
    "travelDistance" : 20985,
    "travelCost" : 0,
    "serviceTime" : 30,
    "serviceTimeCost" : 0,
    "tripNumber" : 0,
    "orders" : [ 
        {
            "orderId" : "AQ137O1701233",
            "SIZE1" : "23",
            "SIZE2" : "402",
            "SIZE3" : "30"
        }
    ],
    "stopId" : "H1iirfhisW"
}, 
{
    "sequence" : 3,
    "locationId" : "332228",
    "lat" : 25.221368,
    "lng" : 55.265915,
    "stopName" : "332228",
    "locationType" : "service",
    "serviceType" : "Delivery",
    "arrivalTime" : 39137,
    "departureTime" : 39167,
    "travelTime" : 974,
    "travelDistance" : 5717,
    "travelCost" : 0,
    "serviceTime" : 30,
    "serviceTimeCost" : 0,
    "tripNumber" : 0,
    "orders" : [ 
        {
            "orderId" : "AQ110O1705036",
            "SIZE1" : "60",
            "SIZE2" : "1046",
            "SIZE3" : "68"
        }
    ],
    "stopId" : "H1csHM3jjb"
}]

var arrOut = [];

array.forEach(function(value) {
  var existing = arrOut.filter(function(v, i) {
    return v.locationId == value.locationId;
  });
  if (existing.length) {
    var existingIndex = arrOut.indexOf(existing[0]);
    arrOut[existingIndex].orders = arrOut[existingIndex].orders.concat(value.orders);
  } else {
    if(Array.isArray(value.orders)){
      value.orders = value.orders
      arrOut.push(value); 
    }
  }
});


document.write('<pre>' + JSON.stringify(arrOut, 0, 4) + '</pre>');


2
使用对象作为映射(这里是b)是标准的做法:
var b = {}, arr = [];
for (var id in a) {
  var oa = a[id], ob = b[oa.id];
  if (!ob) arr.push(ob = b[oa.id] = {}); 
  for (var k in oa) ob[k] = k==='id' ? oa.id : (ob[k]||0)+oa[k];
}
console.log(arr)

如果有什么不明显的地方,请告诉我,我会写一个更详细的答案。 - Denys Séguret
你在第一次修订中忘记了 id,哈哈。当我想询问时,你已经删除了帖子。点赞! - Bergi

0
这是我繁琐的方法: fiddle: http://jsfiddle.net/hN8b6/5/
var a = [{
    "id": "abcd",
        "val1": 1,
        "val2": 1,
        "val3": 0
}, {
    "id": "abcd",
        "val1": 1,
        "val2": 1,
        "val3": 1
}, {
    "id": "efgh",
        "val1": 0,
        "val2": 0,
        "val3": 1
}];

// clone a
a2 = JSON.parse(JSON.stringify(a));

// make sure elements with the same id are next to each other
a2.sort(function (x, y) {
    if (x['id'] < y['id']) {
        return -1;
    }
    if (x['id'] > y['id']) {
        return 1;
    }
    return 0;
});

// iterate over each one, if this one has the same id as the previous one, accumulate
// else add to b
var lastId;
var b = [];
for (var i = 0; i < a2.length; i++) {
    if (lastId == a2[i]['id']) {
        b[b.length-1]['val1'] += a2[i]['val1'];
        b[b.length-1]['val2'] += a2[i]['val2'];
        b[b.length-1]['val3'] += a2[i]['val3'];
    } else {
        b[b.length] = (a2[i]);
        lastId = a2[i]['id'];
    }
}

console.log(b);

你不觉得这有点乏味吗? - Denys Séguret
1
不要修改 a 中的对象! - Bergi
...或者对此发出警告。尽管它看起来像是危险的做法,但这可能是OP希望实现的行为。 - Denys Séguret
感谢大家的建议。我已经做出了更改。 - Fabricator
哦,对了,我甚至错过了a被重新排序的事实。但我实际上担心的是修改数组中的对象! - Bergi
抱歉,感谢你发现了这个问题。我刚学会了一种克隆对象数组的方法。 - Fabricator

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