【问题标题】:Best way to summarize data for an array of objects using JavaScript and lodash使用 JavaScript 和 lodash 为对象数组汇总数据的最佳方法
【发布时间】:2014-10-21 21:35:33
【问题描述】:

我有一个对象数组,我正在寻找对数据进行分组和汇总的最佳最有效方法。目前我有几百行代码和大量的“for each”语句,我知道有很多更简单的方法可以做到这一点,但我就是无法让它完全发挥作用。

这是我的数据的一个小样本。对于任何给定的数据集,我可能有数百种产品。每个产品都有五颗星,并且可以为星星指定三个值之一(已获得、未获得或进行中)。我的目标是查看每个值中有多少分配给每个星的摘要。

[{
  Product: "A"
  star1: "Not Earned"
  star2: "In Progress"
  star3: "Earned"
  star4: "Not Earned"
  star5: "In Progress"
},{
  Product: "B"
  star1: "In Progress"
  star2: "Not Earned"
  star3: "In Progress"
  star4: "Earned"
  star5: "Earned"
}]

最后我会看到类似这样的结果:我意识到我的对象和数组格式有点偏离,这也是我寻求帮助的另一个原因。我也在使用 JavaScript 和 lodash。

Results= [{
   star1:{
      In Progress: 50,
      Not Earned: 32,
      Earned: 1
    },{
   star2:{
      In Progress: 10
      Not Earned: 14,
      Earned: 11
    },{
   star3:{
      In Progress: 45,
      Not Earned: 25,
      Earned: 19
    }]

我该怎么做?

【问题讨论】:

  • 我不知道所有这些数字是从哪里来的......
  • 那么还有更多的产品,这些都是总和?
  • "对于任何给定的数据集,我可能有数百个产品。"如果只有数百个,您可以在没有世界上最快的方法的情况下漂亮/懒惰地完成它,这听起来很好地使用了下划线。
  • 感谢下划线的推荐。我发现了一个使用下划线解决的类似问题,所以我将关闭这个问题......stackoverflow.com/questions/14430321/…
  • 是的,我想groupBycountBy 应该这样做

标签: javascript arrays angularjs object lodash


【解决方案1】:

这是一种方法,可能不是最快的,但它可以工作并且不会产生任何临时变量。除了单个数组 var name (r) 之外,它没有硬编码到数据中,不需要任何库来运行(除了在恐龙浏览器中),而且它很“简单”:

var r=[{
  Product: "A",
  star1: "Not Earned",
  star2: "In Progress",
  star3: "Earned",
  star4: "Not Earned",
  star5: "Earned"
},{
  Product: "B",
  star1: "In Progress",
  star2: "Not Earned",
  star3: "In Progress",
  star4: "Earned",
  star5: "Earned"
},,{
  Product: "C",
  star1: "In Progress",
  star2: "Not Earned",
  star3: "Not Earned",
  star4: "Earned",
  star5: "In Progress"
}];

var sums = {}; // A count holder

Object.keys(r[0]).forEach(function(k){ // For each key in the data of a single data object
     this[k]=r.map(function(o){ return o[k] }) // Pluck values
        .map(function(w){
             if(this[w]){this[w]++;}else{this[w]=1;} // Count values using an object
             return this;
         },{}).pop();  // Take just one of the count object copies (poor-man's reduce with this)
}, sums);

// View result:
JSON.stringify(sums, null, "\t")
/* == {
    "Product": {
        "A": 1,
        "B": 1,
        "C": 1
    },
    "star1": {
        "Not Earned": 1,
        "In Progress": 2
    },
    "star2": {
        "In Progress": 1,
        "Not Earned": 2
    },
    "star3": {
        "Earned": 1,
        "In Progress": 1,
        "Not Earned": 1
    },
    "star4": {
        "Not Earned": 1,
        "Earned": 2
    },
    "star5": {
        "Earned": 2,
        "In Progress": 1
    }
*/

基本思想是把每个键下的所有值都取出来,然后对这些值进行计数。 这种两遍解决方案可能比硬编码的单一用途例程慢一点,但它不需要手动编码的 reduce 函数。

如果需要,您可以默认为零,我不确定这两个示例对象是否包含您的集合包含的所有可能值...

【讨论】:

  • +1 表示通用问题的通用解决方案。请记住,当使用纯 javascript 时,实现可以而且会有所不同。环境一致性是我选择坚持问题中提到的 lodash 库的原因。
  • Object.keys()、[].forEach 和 [].map() 在支持它们的浏览器中的行为都是相同的,而对于不应该遵循规范的浏览器则使用 polyfill。下划线/lodash 有助于提高非泛型迭代的速度(参见 _.map 和 U.map 与danml.com/mofun/#Performance 上的 r.map 相比),以及 _.isArray() 之类的东西,但核心数组迭代方法,恕我直言,在原版中“足够好”可以在生产中使用。
  • 这是一种恭维和赞成,@JSilva 似乎无法召集 :) 感谢您的链接。你的 mofun 库看起来很干净。
  • 我喜欢这个实现。我最终选择了一条不同的路线并创建了一个名为 starProgress 的占位符对象。然后我传入我的数据集并使用 lodash countby。效果很好,但我的主要类别是静态的,这就是为什么我选择您的解决方案更具动态性。 starProgress.forEach(function(star) { _.countBy(d, product); })
【解决方案2】:

您正在寻找“reduce”函数。

类似下面的东西应该买单。

var products = [{
    Product: "A",
    star1: "Not Earned",
    star2: "In Progress",
    star3: "Earned",
    star4: "Not Earned",
    star5: "In Progress",
},{
    Product: "B",
    star1: "In Progress",
    star2: "Not Earned",
    star3: "In Progress",
    star4: "Earned",
    star5: "Earned",
}];

function countStars(accumulator, product) {
    for(var prop in accumulator) {
        accumulator[prop][product[prop]] += 1;
    };

    return accumulator;
}

var starTemplate = {
    "In Progress": 0,
    "Not Earned": 0,
    "Earned": 0,
};

var initialAccumulator = {
    star1: _.clone(starTemplate),
    star2: _.clone(starTemplate),
    star3: _.clone(starTemplate),
    star4: _.clone(starTemplate),
    star5: _.clone(starTemplate),
};


var result = _.reduce(products, countStars, initialAccumulator);

当然,这可以根据需要使用一些生成器函数来改进。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-11-21
    • 1970-01-01
    • 1970-01-01
    • 2015-09-23
    • 1970-01-01
    • 1970-01-01
    • 2020-11-26
    • 1970-01-01
    相关资源
    最近更新 更多