【问题标题】:Combine/merge objects in array based upon common value根据共同值组合/合并数组中的对象
【发布时间】:2012-12-19 07:11:54
【问题描述】:

我有一个类似下面的数组。

[ { 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' } ]

我需要让它看起来像这样

[ { 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' } ]

到目前为止,我已经使用 underscore.js 制作了这个 reduce 函数。

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;
    }, {});
}

这会吐出以下内容。

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

这是减少的好工作吗?我怎样才能以我想要的方式获得它?

【问题讨论】:

  • reduce 不太适合此任务。考虑从groupBy 开始,然后是map

标签: javascript object underscore.js reduce


【解决方案1】:

试试这样的:

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

this jsfiddle

【讨论】:

  • 非常正确。更新的 jsfiddle 已经修复了它,所以我用它替换了它。谢谢!
【解决方案2】:

这样的简单解决方案怎么样:

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

可能这里唯一需要解释的是我们减去负数而不是加法的那一行。这只是为了避免字符串连接,因为“数量”中的值是字符串。


超级精简版,去掉不需要的大括号和分号……只是为了好玩。将订单和数量保留为字符串,使用数量!= 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
}

【讨论】:

  • 此解决方案缺少 sku TEA-BLCK 的项目。
  • @ThomasReggi 没问题,您可能会喜欢普通的解决方案 :)
【解决方案3】:

我参加聚会有点晚了,但听起来很有趣,所以..

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;
 }, []) );

这里我们对数组进行预排序,然后在累加器的开头添加元素。 GGG 已经谈到了字符串。

http://jsfiddle.net/EqGUe/

【讨论】:

  • 很好...功能齐全,没有依赖关系,满足所有要求,适用于 1 以外的数量,将数量保留为字符串。不过,仅限 ES5。 +1
  • @GGG 是的,但是使用es5shim,您甚至可以将reduce 提供给IE6。
  • 我不认为 IE 有 Array#reduce 直到像 9...所以毕竟可能依赖 ;)
【解决方案4】:

也有点晚了,但锻炼很有趣 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;
});

【讨论】:

    【解决方案5】:

    这会更新 benekastah 的答案并处理超过 1 的数量... 但我确实冒昧地将数量更改为整数

    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>");
    ​
    

    【讨论】:

    • 即使在我的代码中,数量永远不会超过一个。我更喜欢这个。
    【解决方案6】:

    从技术上讲,这是完整的答案。从字符串到字符串。对不起各位。

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

    【讨论】:

    • 为什么所有 parseFloat / toString 的东西,而不仅仅是 return memo - -item.quantity + '';
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-02-26
    • 2018-04-15
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 1970-01-01
    • 2019-03-26
    相关资源
    最近更新 更多