【问题标题】:Find average value for array of hashes using multiple group by使用多个分组查找哈希数组的平均值
【发布时间】:2016-01-23 19:10:35
【问题描述】:

基于Summarize array of objects and calculate average value for each unique object name 我可以部分解决我的问题。我确实按 ed_id 分组,但我需要按 ed_id 分组,然后是 el_id 并根据这些分组获得平均值,所以这里是我的哈希数组:

a = [
{
 ed_id: 1,
 el_id: 127,
 value: 2
},
{
 ed_id: 1,
 el_id: 127,
 value: 6
},
{
 ed_id: 1,
 el_id: 129,
 value: 3
},
{
 ed_id: 1,
 el_id: 129,
 value: 13
},
{
 ed_id: 2,
 el_id: 127,
 value: 5
},
{
 ed_id: 2,
 el_id: 127,
 value: 9
},
{
 ed_id: 2,
 el_id: 129,
 value: 10
 }
]

所以最终的哈希数组需要如下所示:

b = [
{
 ed_id: 1,
 el_id: 127,
 value: 4
},
{
 ed_id: 1,
 el_id: 129,
 value: 8
},
{
 ed_id: 2,
 el_id: 127,
 value: 7
},
{
 ed_id: 2,
 el_id: 129,
 value: 10
 }
]

谢谢!

【问题讨论】:

  • 如果您可以按ed_id 分组,那么将结果按el_id 分组应该不会那么麻烦
  • 我确定这不是什么大问题,但我在解决这个问题时遇到了麻烦

标签: javascript group-by underscore.js average


【解决方案1】:

使用的方法/功能:

Array.prototype.reduce(callback[, initialValue]): reduce() 方法对累加器和数组的每个值(从左到右)应用一个函数,以将其减少为单个值。

Object.prototype.keys(obj): Object.keys() 方法返回给定对象自己的可枚举属性的数组,其顺序与 for...in 循环提供的顺序相同(区别在于 for -in 循环也枚举原型链中的属性)。

var data = [
  { ed_id: 1, el_id: 127, value: 2  },
  { ed_id: 1, el_id: 127, value: 6  },
  { ed_id: 1, el_id: 129, value: 3  },
  { ed_id: 1, el_id: 129, value: 13 },
  { ed_id: 2, el_id: 127, value: 5  },
  { ed_id: 2, el_id: 127, value: 9  },
  { ed_id: 2, el_id: 129, value: 10 }
]


// group the data
var groupedData = data.reduce(function(l, r) {
  // construct a unique key out of the properties we want to group by
  var key = r.ed_id + "|" + r.el_id;

  // check if the key is already known
  if (typeof l[key] === "undefined") {
    // init with an "empty" object
    l[key] = {
      sum: 0,
      count: 0
    };
  }
  
  // sum up the values and count the occurences
  l[key].sum += r.value;
  l[key].count += 1;

  return l;
}, {});

console.log(JSON.stringify(groupedData));
//{"1|127":{"sum":8,"count":2},"1|129":{"sum":16,"count":2},"2|127":{"sum":14,"count":2},"2|129":{"sum":10,"count":1}}


// calculate the averages
var avgGroupedData = Object.keys(groupedData)
  // iterate over the elements in <groupedData> and transform them into the "old" format
  .map(function(key) {
    // split the constructed key to get the parts
    var keyParts = key.split(/\|/);

    // construct the "old" format including the average value
    return {
      ed_id: parseInt(keyParts[0], 10),
      el_id: parseInt(keyParts[1], 10),
      value: (groupedData[key].sum / groupedData[key].count)
    };
  });

console.log(JSON.stringify(avgGroupedData));
// [{"ed_id":1,"el_id":127,"value":4},{"ed_id":1,"el_id":129,"value":8},{"ed_id":2,"el_id":127,"value":7},{"ed_id":2,"el_id":129,"value":10}]

【讨论】:

    【解决方案2】:

    这应该做你想做的事。为了便于阅读,分解成小函数:

    var groupingKey = function(item){
        return item.ed_id + "/" + item.el_id
    }
    
    var sum = function(total, item){
        return total + item.value;
    }
    
    var average = function(items){
        return _.reduce(items, sum, 0) / items.length;
    }
    
    var groupsToResult = function(groups){
    
        return {
            ed_id: groups[0].ed_id,
            el_id: groups[0].el_id,
            value: average(groups)
        }
    }
    
    var result = _.chain(a)
        .groupBy(groupingKey)
        .map(groupsToResult)
        .value();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-28
      • 1970-01-01
      • 2018-06-14
      • 1970-01-01
      • 2016-10-31
      相关资源
      最近更新 更多