简体   繁体   中英

javascript/underscore: find objects by property in an array, and combine them

If I have an array of objects that looks like this:

[{id:1,product:'widget',quantity:10}, {id:2,product:'foobar',quantity:5}, {id:3,product:'widget',quantity:5}]

Is there an elegant way in javascript to find objects with the same name, and combine the quantities into the first object, and remove the rest?

The resulting array would look like this:

[{id:1,product:'widget',quantity:15}, {id:2,product:'foobar',quantity:5}]

Right now I'm creating a new array, iterating over the existing array, finding everything with a particular name, doing the sum, and then dumping it into the new array. That all seems overly complicated. I'm using underscore to handle a lot of the heavy lifting.

Thanks!

You could groupBy product and then map the resulting groups to get the required structure. Reduce is used to sum the quantities:

    var groups = _.chain(data)
        .groupBy('product')
        .map( function(group){
            return {
                id: group[0].id,
                product: group[0].product,
                quantity: _.reduce(group, function(memo, value){ return memo + value.quantity; }, 0 )
            }
        })
        .value();

Try using a hash table (an Object in Javascript):

var data = new Array(
    {id:1,product:'widget',quantity:10},
    {id:2,product:'foobar',quantity:5},
    {id:3,product:'widget',quantity:5}
);
var temp = new Object();
var newdata = new Array();

// Stuff your quantities into the hash table
for (var i=0; i<data.length; i++) {
    // If the product doesn't exist yet, create it and set the quantity to 0
    if (!temp.hasOwnProperty(data[i].product)) {
        temp[data[i].product] = 0;
    }
    // Increment the product quantity
    temp[data[i].product] += data[i].quantity;
}

// Split out the hash table into an array
for (product in temp) {
    newdata.push({"id":newdata.length+1, "product":product, "quantity":temp.product});
}

Are you ok with the result not being a formal array but instead an traditional Object? Because really, an array is just a special type of Object. This way you can access it as if it were an associative array, and you can access based on the name of the product, which seems to be what you care about:

var results = {};
for(var i = 0; i < yourarr.length; ++i) {
  if(!results.hasOwnProperty(yourarr[i].product)) {
    results[yourarr[i].product] = {};
    results[yourarr[i].product].id = yourarr[i].id;
    results[yourarr[i].product].quantity = yourarr[i].quantity;
  }

  results[yourarr[i].product].quantity += yourarr[i].quantity;
}

//Can now access by doing say, console.log(results.widget);
//To loop through, you can do:
for(var key in results) {
  if(results.hadOwnProperty(key) { //Needed to ensure you don't access prototype elements
    console.log(results.key);
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM