【问题标题】:Using Underscore.js To Merge/Combine and Sum Array Entries使用 Underscore.js 合并/组合和求和数组条目
【发布时间】:2014-09-25 02:43:37
【问题描述】:

我有 2 个 JSON 对象数组,我希望将它们合并/组合在一起,然后总结任何匹配条目的数量。

这两个数组包含相同的结构,一个表示需要使用的设备列表...

var required = [
    { SerialisedEquipment: { SerialNo: "ser855212" }, Type: undefined, Serialised: true, Quantity: 1 },
    { SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Serialised: true, Quantity: 1 },
    { SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Serialised: false, Quantity: 5 },
    { SerialisedEquipment: undefined, Type: { ItemId: "itm11025" }, Serialised: false, Quantity: 2 }];

...另一个代表实际使用过的设备列表。

var used = [
    { SerialisedEquipment: { SerialNo: "ser663033" }, Type: undefined, Serialised: true, Quantity: 1 },
    { SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Serialised: true, Quantity: 1 },
    { SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Serialised: false, Quantity: 2 }];

我可以访问 underscore.js,并且一直在尝试使用 _.groupBy 和 _.reduce 方法来尝试获得我想要的结果,但没有成功。我希望达到的结果是:

var result = [
    { SerialisedEquipment: { SerialNo: "ser663033" }, Type: undefined, Used: 1, Expected: 0, Remaining: 0 },
    { SerialisedEquipment: { SerialNo: "ser288945" }, Type: undefined, Used: 1, Expected: 1, Remaining: 0 },
    { SerialisedEquipment: { SerialNo: "ser855212" }, Type: undefined, Used: 0, Expected: 1, Remaining: 1 },
    { SerialisedEquipment: undefined, Type: { ItemId: "itm71770" }, Used: 2, Expected: 5, Remaining: 3 },
    { SerialisedEquipment: undefined, Type: { ItemId: "itm11025" }, Used: 0, Expected: 2, Remaining: 2 }];

我也一直在研究 underscore 提供的一些 Array 方法,但我不确定如何使用这些方法来指定合并条件。有人对实现这一目标的最佳方法有什么建议吗?

更新

我已经设法获得了两个数组的合并列表,删除了重复项...

// Split based on the serialised flag - so I know to look at either the serialNo or Type property
var isSerialised = _.groupBy(required, function (equip) {
    return equip.Serialised;
});

// Get all the required serialised equipment that is not already in the used list
var serialised = _.filter(isSerialised[true], function (value) {
    return (!_.some(used, function (equip) {
        return equip.SerialisedEquipment && equip.SerialisedEquipment.SerialNo == value.SerialisedEquipment.SerialNo;
    }));
});

// Get all the required types that are not already in the used list
var types = _.filter(isSerialised[false], function (value) {
    return (!_.some(used, function (equip) {
        return equip.Type && equip.Type.ItemId == value.Type.ItemId;
    }));
});

// Combine the equipment that is not in the list with the equipment that is in the list
var result = _.union(used, serialised, types);

我认为现在只是用所需设备列表循环遍历此结果列表并根据序列号或类型总结匹配的设备。

【问题讨论】:

  • 嗨,qtheintro,你能发布你的代码来查看你的错误吗!
  • 嗨 Papouche,我一直在尝试通过使用下划线库来获得结果,但我并没有真正得到错误,但我的代码目前离正确的结果还很远,我'我更加努力地思考问​​题并寻找可能指向正确方向的指针。

标签: javascript arrays underscore.js


【解决方案1】:

有时想大量使用库会让您错过更简单的算法:

var resultsById = {};
function getTemporaryId(value) {
    return value.SerialisedEquipment ? value.SerialisedEquipment.SerialNo : value.Type.ItemId;
}
function getResultForValue(value) {
    var id = getTemporaryId(value);
    if(!resultsById[id]) {
        resultsById[id] = {
            SerialisedEquipment: value.SerialisedEquipment,
            Type: value.Type,
            Used: 0,
            Expected: 0,
            Remaining: 0
        };
    }
    return resultsById[id];
}
_.each(required, function(value) {
    var result = getResultForValue(value);
    result.Expected += value.Quantity;
    result.Remaining += value.Quantity;
});
_.each(used, function(value) {
    var result = getResultForValue(value);
    result.Used += value.Quantity;
    result.Remaining = Math.max(result.Remaining - value.Quantity, 0);
});

var merged = _.values(resultsById);

如果你真的想使用很多下划线,你可以试试这个解决方案:

var requiredValues = _.map(required, (function(value){
    //maybe want to clone value? value = _.clone(value);
    value.Used = 0;
    value.Expected = value.Quantity;
    return value;
}));
var usedValues = _.map(used, (function(value){
    //maybe want to clone value? value = _.clone(value);
    value.Used = value.Quantity;
    value.Expected = 0;
    return value;
}));
var mergedValues = _.chain(requiredValues.concat(usedValues))
    .groupBy(function(value){
        return value.SerialisedEquipment ? value.SerialisedEquipment.SerialNo : value.Type.ItemId;
    })
    .map(function(values) {
        var memo = {
            SerialisedEquipment: values[0].SerialisedEquipment,
            Type: values[0].Type,
            Used: 0,
            Expected: 0,
            Remaining: 0
        };
        return _.reduce(values, function(memo, value) {
            memo.Used += value.Used;
            memo.Expected += value.Expected;
            memo.Remaining = Math.max(memo.Expected - memo.Used, 0);
            return memo;
        }, memo)
    })
    .values()
    .value();

【讨论】:

  • 我努力接近一个解决方案,而您想出了两个!非常感谢您的时间和帮助,还有一些额外的要求,但我可以对您的解决方案进行调整。再次感谢,我会将此标记为解决方案。
【解决方案2】:

你可以只使用 Array.concat() 方法:

var result = required.concat(used);

它会为你合并。

编辑

虽然如果你想使用 undescore 方法 _.union(arr1,arr2) 是给你的!

【讨论】:

  • 感谢 Arsenii,将数组合并在一起,但您知道是否有办法汇总将由 concat/union 合并的条目?
  • 我不确定我是否清楚地理解“总结条目”是什么意思。如我所见,您有七个不同的对象,每个对象只有一个条目..
  • 我明白了。如果我有任何解决方案,我会考虑解决方案并写信给你。 BR
  • 您好,Arsenii,感谢您的帮助。正如您已经发现的那样,我也在寻找两个列表中的已使用、预期和剩余的设备。我已经设法将列表合并在一起 - 我知道丑陋的代码 - 并更新了问题,所以我现在正在研究如何汇总数量。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-06
  • 2021-12-27
  • 1970-01-01
  • 2014-11-22
相关资源
最近更新 更多