由相同元素的数组的Sum对象

时间:2015-10-22 13:58:47

标签: javascript underscore.js

var data = [
   {id: 1, quantity: 10, category: 'A'},
   {id: 2, quantity: 20, category: 'B'},
   {id: 1, quantity: 30, category: 'A'},
   {id: 1, quantity: 30, category: 'Z'},
   {id: 2, quantity: 40, category: 'D'}
];

var totalPerType = {};
for (var i = 0, len = data.length; i < len; ++i) {
    totalPerType[data[i].id] = totalPerType[data[i].id] || 0;
    totalPerType[data[i].id] += data[i].quantity;
}
var out = _.map(totalPerType, function (id, quantity) {
    return {'id': id, 'quantity': quantity};
});
console.log(out);

我的代码目前总结了具有相同ID的对象的数量。它返回

[ {id:1, quantity:70}, {id:2, quantity:60} ]

如何根据ID和类别获取对象的总和?

例如,我需要这样的输出:

[ 
     {id:1, quantity:40, category:A}, 
     {id:1, quantity:30, category:Z}, 
     {id:2, quantity:20, category:B}, 
     {id:, quantity:40, category:D} 
]

我想要简单的javascript和下划线的答案。

3 个答案:

答案 0 :(得分:3)

使用vanilla js。

var tmp = {}

data.forEach(function (item) {
    var tempKey = item.id + item.category;
    if (!tmp.hasOwnProperty(tempKey)) {
        tmp[tempKey] = item;
    } else {
        tmp[tempKey].quantity += item.quantity;
    }
});

var results = Object.keys(tmp).map(function(key){
    return tmp[key];
});

请注意,这将更改原始数据中的对象。在添加到item对象时,如果不需要,则需要复制tmp

&#13;
&#13;
var data = [
   {id: 1, quantity: 10, category: 'A'},
   {id: 2, quantity: 20, category: 'B'},
   {id: 1, quantity: 30, category: 'A'},
   {id: 1, quantity: 30, category: 'Z'},
   {id: 2, quantity: 40, category: 'D'}
];

var tmp = {}

data.forEach(function (item) {
    var tempKey = item.id + item.category;
    if (!tmp.hasOwnProperty(tempKey)) {
        tmp[tempKey] = item;
    } else {
        tmp[tempKey].quantity += item.quantity
    }
});

var results = Object.keys(tmp).map(function(key){
    return tmp[key];
});

document.body.innerHTML ='<pre>' + JSON.stringify(results,null,4) +'</pre>';
&#13;
&#13;
&#13;

答案 1 :(得分:1)

以下是使用下划线的解决方案:

// used when calling reduce to sum the quantities of a group of items
var sumQuantity = function(total, item){
    return total + item.quantity;
}

// used by groupBy to create a composite key for an item
var itemKey = function(item){
    return item.id + '/' + item.category;
}

// used to convert a group of items to a single item 
var groupToSummedItem = function(group){
    return {
        id: group[0].id,
        category: group[0].category,
        quantity: _.reduce(group, sumQuantity, 0)
    }
}

// the bit that does the work
var result = _.chain(data)
    .groupBy(itemKey)
    .map(groupToSummedItem)
    .value();

答案 2 :(得分:1)

已经有两个好的答案,但我想我会展示一个更灵活的ES6解决方案。它使用Map并通过从需要匹配的属性创建字符串为每条记录创建唯一键。使用键将记录添加到地图中,并根据需要对值进行求和。

完成后,它将地图转换为数组并返回新数组;

var data = [  // test data
   {id: 1, quantity: 10, category: 'A'},
   {id: 2, quantity: 20, category: 'B'},
   {id: 2, quantity: 20, category: 'Z'},
   {id: 2, quantity: 20, category: 'D'},
   {id: 1, quantity: 30, category: 'A'},
   {id: 1, quantity: 30, category: 'Z'},
   {id: 2, quantity: 40, category: 'D'}
];

// function to collapse records in an array of objects;
// arr is the array of objects
// match is an array of property names that need to be matched
// sum us an array of property names that need to be summed
function collapse ( arr, match, sum ) { // bad name but just can't remember what this should be called
    // define vars
    var newArray, key, processRecord

    // define function
    // function to process each record
    processRecord = function( item ) {
        // define vars
        var key, getKey, sumFields, record;
        // define functions
        getKey = function ( field ) { key += item[field]; } // Creates a key 
        sumFields = function ( field ) { record[field] += item[field];} // sums fields

        // code
        key = "";  // create a blank key
        match.forEach( getKey );  // create a unique key
        if(newArray.has( key ) ){  // does it exist
            record = newArray.get( key );  // it does so get the record
            sum.forEach( sumFields );  // sum the fields
        }else{
            newArray.set( key, item ); // the key does not exist so add new record
        }
    }

    // code
    newArray = new Map();  // create a new map
    arr.forEach( processRecord );  // process each record
    return ( [...newArray.values()] ); // convert map to array and return it
}

// call the function matching id and category summing quantity
var a1 = collapse( data, ["id" , "category"], ["quantity"] );

// call the function matching id only summing quantity
var a2 = collapse( data, ["id"], ["quantity"] );

// call the function matching category only summing quantity
var a3 = collapse( data, ["category"], ["quantity"] );

// call the function matching all fields and summing quantity
var a4 = collapse( data, ["id, "quantity", "category"], ["quantity"] );