使用Underscore.js合并/组合和求和数组项

Using Underscore.js To Merge/Combine and Sum Array Entries

本文关键字:求和 数组 组合 Underscore js 合并 使用      更新时间:2023-09-26

我有两个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 }];

我可以访问undercore.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 }];

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

更新

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

// 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);

我认为现在只是一个循环通过这个结果列表和所需设备列表,并根据序列号或类型总结匹配的设备的情况。

有时想要使用库会让你错过更简单的算法:

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();

您只需使用Array.concat()方法:

var result = required.concat(used);

它会让你合并。

编辑

不过,如果你想使用不理想的方法_.union(arr1,arr2)适合你!