Combine/merge objects in array based upon common v

2019-05-14 08:56发布

I have an array like the following.

[ { sku: 'TEA-BLCK', price: '10', quantity: '1' },
  { sku: 'TEA-ELGY', price: '10', quantity: '1' },
  { sku: 'TEA-CHAI', price: '10', quantity: '1' },
  { sku: 'TEA-GREN', price: '10', quantity: '1' },
  { sku: 'TEA-ELGY', price: '10', quantity: '1' },
  { sku: 'TEA-MINT', price: '10', quantity: '1' } ]

I need to make it look like this

[ { sku: 'TEA-BLCK', price: '10', quantity: '1' },
  { sku: 'TEA-ELGY', price: '10', quantity: '2' },
  { sku: 'TEA-CHAI', price: '10', quantity: '1' },
  { sku: 'TEA-GREN', price: '10', quantity: '1' },
  { sku: 'TEA-MINT', price: '10', quantity: '1' } ]

I got so far to make this reduce function using underscore.js.

var reduce = function(){
    return _.reduce(line_items, function(quant, item) {
        quant[item.sku] = (typeof(quant[item.sku]) !== "undefined") ? quant[item.sku] : 0 ;
        quant[item.sku] = parseFloat(item.quantity) + quant[item.sku];
        return quant;
    }, {});
}

Which spits out the following.

{ 'TEA-BLCK': 1,
  'TEA-ELGY': 1,
  'TEA-CHAI': 2,
  'TEA-GREN': 1,
  'TEA-MINT': 1 }

Is this a good job for reduce? How can I get it the way I want?

6条回答
冷血范
2楼-- · 2019-05-14 09:21

I was a bit late to the party, but it sounded so fun, so..

JSON.stringify(
[ { sku: 'TEA-BLCK', price: '10', quantity: '1' },
  { sku: 'TEA-ELGY', price: '10', quantity: '1' },
  { sku: 'TEA-CHAI', price: '10', quantity: '1' },
  { sku: 'TEA-GREN', price: '10', quantity: '1' },
  { sku: 'TEA-ELGY', price: '10', quantity: '1' },
  { sku: 'TEA-MINT', price: '10', quantity: '1' } ].sort( function (a, b) {
   return a.sku < b.sku;
} ).reduce( function (a,v) {
   if ( !a[0] || a[0].sku !== v.sku  ) {
      a.unshift(v);
   } else {
      // notice the very inefficient str -> number -> str conversion
      a[0].quantity = 1*a[0].quantity + 1*v.quantity + '';
   }

   return a;
 }, []) );

Here we pre-sort the array, and then add elements to the beginning of accumulator. And GGG have already said about strings.

http://jsfiddle.net/EqGUe/

查看更多
神经病院院长
3楼-- · 2019-05-14 09:23

Technically this is the complete answer. From string to string. Sorry guys.

var line_items = [
    { sku: 'TEA-BLCK', price: '10', quantity: "2" },
    { sku: 'TEA-ELGY', price: '10', quantity: "3" },
    { sku: 'TEA-CHAI', price: '10', quantity: "1" },
    { sku: 'TEA-GREN', price: '10', quantity: "1" },
    { sku: 'TEA-ELGY', price: '10', quantity: "1" },
    { sku: 'TEA-MINT', price: '10', quantity: "1" }
];

// Group items by sku.
var line_items_by_sku = _(line_items).groupBy(function (item) { return item.sku; });

// Get the new line_items array based on the grouped data.
line_items = _(line_items_by_sku).map(function (items) {
    var item = items[0];
    item.quantity = _.reduce(items, function(memo, item){ return memo + parseFloat(item.quantity); }, 0);
    item.quantity = item.quantity.toString();
    return item;
});

document.write("<pre>"+JSON.stringify(line_items, null, " ")+"</pre>");
查看更多
淡お忘
4楼-- · 2019-05-14 09:35

What about a simple solution like this:

function reduce(array) {
    var out = [];
    var indexBySku = {};
    for (var i = array.length; i--;) {
        if (!indexBySku[array[i].sku]) {
            indexBySku[array[i].sku] = out.length;
            out.push(array[i]);
        } else {
            out[indexBySku[array[i].sku]].quantity -= -array[i].quantity;
        }
    }
    return out;
}

http://jsfiddle.net/waV6H/1

Probably the only thing that needs explanation here is the line where we subtract a negative instead of adding. This is just to avoid string concatenation, since the values in "quantity" are strings.


Super condensed version, dropping unneeded braces and semicolons... just for fun. Preserves order and quantity as string, works with quantity != 1.

function reduce(array) {
    var out = [], indexBySku = {}, len = array.length, i, j
    for (i = 0; i < len; i++)
        (j = indexBySku[array[i].sku]) ?  
            out[j].quantity = out[j].quantity - -array[i].quantity + '' :
            indexBySku[array[i].sku] = out.push(array[i]) - 1
    return out
}
查看更多
看我几分像从前
5楼-- · 2019-05-14 09:36

Try something like this:

var line_items = [
    { sku: 'TEA-BLCK', price: '10', quantity: 2 },
    { sku: 'TEA-ELGY', price: '10', quantity: 3 },
    { sku: 'TEA-CHAI', price: '10', quantity: 1 },
    { sku: 'TEA-GREN', price: '10', quantity: 1 },
    { sku: 'TEA-ELGY', price: '10', quantity: 1 },
    { sku: 'TEA-MINT', price: '10', quantity: 1 }
];

// Group items by sku.
var line_items_by_sku = _(line_items).groupBy(function (item) { return item.sku; });

// Get the new line_items array based on the grouped data.
line_items = _(line_items_by_sku).map(function (items) {
    var item = items[0];
    item.quantity = _.reduce(items, function(memo, item){ return memo + item.quantity; }, 0);
    return item;
});

See this jsfiddle.

查看更多
祖国的老花朵
6楼-- · 2019-05-14 09:40

A bit late as well, but fun to work out http://jsbin.com/amazat/2/

line_items_reduced = _.map(reduce(), function(value, key) {
  var line_item = _.find(line_items, function(line_i){
    return (key === line_i.sku);
  });
  line_item.quantity = value;
  return line_item;
});
查看更多
闹够了就滚
7楼-- · 2019-05-14 09:40

This updates benekastah's answer and handles quantities more than 1... But I did take the liberty to change quantity to an integer

http://jsfiddle.net/xjUDY/3/

var line_items = [
    { sku: 'TEA-BLCK', price: '10', quantity: 2 },
    { sku: 'TEA-ELGY', price: '10', quantity: 3 },
    { sku: 'TEA-CHAI', price: '10', quantity: 1 },
    { sku: 'TEA-GREN', price: '10', quantity: 1 },
    { sku: 'TEA-ELGY', price: '10', quantity: 1 },
    { sku: 'TEA-MINT', price: '10', quantity: 1 }
];

// Group items by sku.
var line_items_by_sku = _(line_items).groupBy(function (item) { return item.sku; });

// Get the new line_items array based on the grouped data.
line_items = _(line_items_by_sku).map(function (items) {
    var item = items[0];
    item.quantity = _.reduce(items, function(memo, item){ return memo + item.quantity; }, 0);
    return item;
});

document.write("<pre>"+JSON.stringify(line_items, null, " ")+"</pre>");
​
查看更多
登录 后发表回答