javascript 带下划线的 Map Reducing 对象

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19547622/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 15:56:19  来源:igfitidea点击:

Map Reducing object with underscore

javascriptmapmapreduceunderscore.jsreduce

提问by vincewilfork

I want to reduce this object to just an object containing product name and average price. What's the fastest way to do it?

我想将此对象减少为仅包含产品名称和平均价格的对象。最快的方法是什么?

var foo = { group1: [
        {
            name: "one",
            price: 100
        },
        {
            name: "two",
            price: 100
        }],
       group2: [
        {
            name: "one",
            price: 200
        },
        {
            name: "two",
            price: 200
        }],
       group3: [
        {
            name: "one",
            price: 300
        },
        {
            name: "two",
            price: 300
        }]
      }

resulting in

导致

var foo2 = [{  
               name: 'one',  
               price: 200
            },{
               name: 'two', 
               price: 200
            }];

Thanks!

谢谢!

采纳答案by Evan

Edit: Leaving this up for now, but I totally forgot about _.flatten, so redmallard's got a much better answer.

编辑:暂时搁置这个,但我完全忘记了 _.flatten,所以 redmallard 得到了更好的答案

If you already know the product names and they appear in every group, you could do the whole thing quickly this way:

如果您已经知道产品名称并且它们出现在每个组中,那么您可以通过以下方式快速完成整个操作:

var productAveragePrices = function ( groups, names ) {
  return _.map( names, function ( name ) {
    var product = { name: name }, productPricesSum = 0;
    _.each( groups, function ( group ) {
      productPricesSum += ( _.findWhere( group, product ).price );
    });
    product.price = productPricesSum / _.size( groups );
    return product;
  });
};
var foo2 = productAveragePrices = function ( foo, ['one', 'two'] );

I put this together, which should work even if your groups have different products (eg "one" in first, second, and fourth group and "two" in first and third):

我把它们放在一起,即使您的团队有不同的产品(例如,第一、第二和第四组中的“一个”和第一和第三组中的“两个”)也应该有效:

var productPriceReducer = function( memo, group ) {
  _.each( group, function( product ) {
    // Grabs the current product from the list we're compiling
    var memoProduct = _.findWhere( memo, { name: product.name });
    if ( !memoProduct ) {
      // If the product doesn't exist, creates a holder for it and its prices
      memoProduct = {
        name: product.name,
        prices: [ product.price ]
      };
      memo.push( memoProduct );
    } else {
      // Otherwise, it just adds the prices to the existing holder.
      memoProduct.prices.push( product.price );
    }
  });
  return memo;
};

// This gets us a list of products with all of their prices across groups
var productPrices = _.reduce( foo, productPriceReducer, [] );

// Then reducing to the average is pretty simple!
var productAveragePrices = _.map( productPrices, function ( product ) {
  var sumPrices = _.reduce( product.prices, function ( memo, price ) {
    return memo + price;
  }, 0 );
  return {
    name: product.name,
    price: sumPrices / product.prices.length
  };
});

You could still do the above in one function with a counter and summing the prices, but this way, you also have the prices in case you want to, say, take the standard deviation or find the mode.

您仍然可以使用计数器在一个函数中执行上述操作并对价格求和,但是这样,您也可以拥有价格,以防万一,例如,采用标准偏差或找到模式。

回答by redmallard

Not to rain on Evan's parade, but here's an alternative that is a bit shorter ;)

不要在埃文的游行中下雨,但这里有一个更短的替代方案;)

result = _.chain(original)
  .flatten()
  .groupBy(function(value) { return value.name; })
  .map(function(value, key) {
    var sum = _.reduce(value, function(memo, val) { return memo + val.price; }, 0);
    return {name: key, price: sum / value.length};
  })
  .value();

See it in action: http://plnkr.co/edit/lcmZoLkrlfoV8CGN4Pun?p=preview

看到它在行动:http: //plnkr.co/edit/lcmZoLkrlfoV8CGN4Pun?p=preview

回答by user239558

I really like redmallard's solution, but I wanted to golf a little.

我真的很喜欢 redmallard 的解决方案,但我想打一点高尔夫球。

Underscore doesn't include a sumfunction, but we can write pretty elegant functional expressions by adding a summixin. This function is known as addin the underscore-contribs repo.

Underscore 不包含sum函数,但我们可以通过添加一个summixin来编写非常优雅的函数表达式。此函数在 underscore-contribs 存储库中称为add

Then we can write:

然后我们可以写:

// Somewhere in the initialization of the program
_.mixin({
  sum : function (arr) {
     return _.reduce(arr, function (s, x) { return s + x;}, 0);
  }
});
result = _.chain(original)
  .flatten()
  .groupBy('name') // shorthand notation
  .map(function (value, key) {
      var sum = _.chain(value).pluck('price').sum().value();
      return { name: key, price: sum / value.length}; 
  })
  .value();

http://plnkr.co/edit/ul3odB7lr8qwgVIDOtM9

http://plnkr.co/edit/ul3odB7lr8qwgVIDOtM9

But then we can also create an avgmixin to expand our toolbelt:

但是我们也可以创建一个avgmixin 来扩展我们的工具带:

// Somewhere in the initialization of the program
_.mixin({
  sum : function (arr) {
     return _.reduce(arr, function (s, x) { return s + x;}, 0);
  },
  avg : function (arr) {
     return _.sum(arr)/arr.length;
  }
});
result = _.chain(original)
  .flatten()
  .groupBy('name') // shorthand notation
  .map(function (value, key) {
      return { name: key, price: _.avg(value)}; 
  })
  .value();