【问题标题】:most efficient way to find average using lodash使用 lodash 求平均值的最有效方法
【发布时间】:2015-03-28 14:16:52
【问题描述】:

我有一个对象数组,对象的数量是可变的 -

var people = [{
  name: john,
  job: manager,
  salary: 2000
},
  {
  name: sam,
  job: manager,
  salary: 6000
},
  {
  name: frodo,
  job: janitor
}];

使用 lodash 求所有经理平均工资的最优雅方法是什么? (我假设我们必须检查一个对象是否是经理,以及该对象是否具有薪水属性)

我在想下面几行 -

_(people).filter(function(name) {
    return name.occupation === "manager" && _(name).has("salary");}).pluck("salary").reduce(function(sum,num) { return sum+num });

但我不确定这是否是正确的方法。

【问题讨论】:

  • 这段代码有效吗? reduce 似乎没有找到 avg,而是返回所有薪水的总和。

标签: javascript underscore.js lodash


【解决方案1】:

为什么所有人都会在这里变得过于复杂?

const people = [
  { name: 'Alejandro', budget: 56 },
  { name: 'Juan',      budget: 86 },
  { name: 'Pedro',     budget: 99 },
];

const average = _.meanBy(people, (p) => p.budget);
console.log(average);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>

根据文档:https://lodash.com/docs/#meanBy

【讨论】:

  • 可以简化为let average = _.meanBy(people, 'budget');。也仅适用于 v4。*
  • @Stalinko 这使它更短,而不是更简单,当您使用 IDE 时,您可以看到预算类型(在 TypeScript 的情况下),或者您可以使用 go to declaration、find references 等。答案很好,他可以做些什么来简化它是使用p => p.budget
  • @Stalinko 不完全是,使用箭头方法省略了计算并使用中间件方法查找“预算”成员,正如 Almis 所说,箭头使 IDE 能够查看数据类型。
  • @FredericYesidPeñaSánchez 让人们决定他们更喜欢什么。无论如何,这两种方法没有太大区别。
【解决方案2】:

“高效”是一个非常模糊的术语。说“高效”可以考虑性能,或者可读性,或者简洁性等等。我认为最可读简洁的解决方案是:

_(people).filter({ job: 'manager'}).filter('salary').reduce(function(a,m,i,p) {
    return a + m.salary/p.length;
},0);

快速的解决方案是不使用 loadash,也不使用任何库,也不使用任何 filterreduce 方法。改用for 循环:

var sum    = 0;
var count  = 0;
for (var i = 0, ii = people.length; i < ii; ++i) {
    var man = people[i];

    if (typeof man.salary !== 'undefined') {
        sum += man.salary;
        ++count;
    }
}
var avg = sum/count;

我认为对于客户端开发可读性在大多数情况下比性能更重要,所以我认为第一个变体是最“高效”的。

【讨论】:

  • 除了 reduce 中的明显错误使其返回总和而不是 OP 问题中的平均值之外,这与他的解决方案有何不同? (真心问,无意批评)
  • a + m.salary/p.length - 看看p.length - 结果是平均值,而不是总和。
  • @lascort 如果您不相信我,您可以自己尝试一下。转到lodash,打开控制台,创建people 数组,然后复制/粘贴我的解决方案。
  • 我并不是说它不起作用,我只是说在我看来这与他所做的相同,但顺序不同。除了他显然在 reduce 函数中犯了一个错误,但我假设这只是一个错字。不过我可能弄错了,我不是 lodash 方面的专家,这就是我问的原因
  • @lascort 问题是“使用 lodash 找到平均值的最有效方法”。我认为这是最“高效”和优雅的方式。我认为这比他自己的解决方案更清楚。好吧,如果有人有更好的想法,他们可以写下自己的答案。如果我发现他们的解决方案更好,我什至会删除我的答案。
【解决方案3】:

lodash v3:

_.sum(people, 'salary') / people.lengthpeople 不能为空)

lodash v4:

_.meanBy(people, 'salary')

【讨论】:

    【解决方案4】:

    我不知道 lowdash,但也许一个简单的 JS 解决方案会帮助你到达那里:

    console.log(people.reduce(function(values, obj) {
                  if (obj.hasOwnProperty('salary')) {
                    values.sum += obj.salary;
                    values.count++;
                    values.average = values.sum / values.count;
                  }
                  return values;
                }, {sum:0, count:0, average: void 0}).average
    ); // 4000
    

    这会将一个对象作为 accumulator 传递给 reduce,该对象具有三个属性:工资总和、工资计数和迄今为止的平均值。它遍历所有对象,将薪水相加,计算有多少对象并计算每次迭代的平均值。最终它会返回该对象(accumulator)并读取 average 属性。

    调用单个内置方法应该比调用 4 个本机函数更快(即更高效)。 “优雅”在情人眼中。 ;-)

    顺便说一句,对象字面量有错误,应该是:

    var people = [{
      name: 'john',
      job: 'manager',
      salary: 2000
    },
      {
      name: 'sam',
      job: 'manager',
      salary: 6000
    },
      {
      name: 'frodo',
      job: 'janitor'
    }];
    

    【讨论】:

      【解决方案5】:
      function average(acc, ele, index) {
          return (acc + ele) / (index + 1);
      }
      
      var result = _.chain(people)
          .filter('job', 'manager')
          .map('salary')
          .reduce( average )
          .value();
      

      【讨论】:

        【解决方案6】:

        使用功能更强大的 lodash 版本 (lodash-fp) 和 es2015,您可以使用箭头函数和自动 curry 来获得更灵活和功能更丰富的解决方案。

        你可以把它放在一个丑陋的衬里:

        const result = _.flow(_.filter(['job', 'manager']), 
            e => _.sumBy('salary', e) / _.countBy(_.has('salary'), e).true)(people);
        

        或者你可以创建一个整洁的 DSL:

        const hasSalary = _.has('salary');
        const countWhenHasSalary = _.countBy(hasSalary);
        const salarySum = _.sumBy('salary');
        const salaryAvg = a => salarySum(a) / countWhenHasSalary(a).true;
        const filterByJob = job => _.filter(['job', job]);
        const salaryAvgByJob = job => _.flow(filterByJob(job), salaryAvg);
        
        const result = salaryAvgByJob('manager')(people);
        

        【讨论】:

          【解决方案7】:

          我能想到的最干净(优雅)的方式是:

          var salariesOfManagers = _(people).filter({job: 'manager'}).filter('salary').pluck('salary');
          var averageSalary = salariesOfManagers.sum() / salariesOfManagers.value().length;
          

          它取项目总和除以项目数,这几乎是平均值的定义。

          太糟糕了,如果你想把它写成简洁的单行代码,代码就会变得不那么清晰了。

          【讨论】:

            【解决方案8】:

            使用lodash/fp 和 ES2016/ES6 可以以更实用的方式完成

            const avg = flow(
                filter({job: 'manager'}), 
                map('salary'),
                mean
            )
            
            console.log(avg(people))
            

            你所做的是 1.获取所有对象'manager'类型 2.从中提取“工资”属性/字段 3. 使用均值函数求平均值

            为了您的方便,这是在 nodejs 上运行的完整版代码。

            'use strict'
            const _ = require('lodash/fp');
            
            const {
                flow,
                filter,
                map,
                mean
            } = _
            
            const people = [{
                name: 'john',
                job: 'manager',
                salary: 2000
            }, {
                name: 'sam',
                job: 'manager',
                salary: 6000
            }, {
                name: 'frodo',
                job: 'janitor'
            }];
            
            const avg = flow(
                filter({job: 'manager'}), 
                map('salary'),
                mean
            )
            
            console.log(avg(people))
            

            【讨论】:

              猜你喜欢
              • 2014-03-03
              • 2016-08-12
              • 2012-07-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多