繁体   English   中英

使用 lodash 查找平均值的最有效方法

[英]most efficient way to find average using lodash

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

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

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

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

 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

“高效”是一个非常含糊的词。 说“高效”,您可以考虑性能可读性简洁性等。 我认为最易读简洁的解决方案是:

_(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;

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

lodash v3:

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

lodash v4:

_.meanBy(people, 'salary')

我不知道 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

此传递一个目的是减少作为具有三个属性累加器:薪金的总和,薪水的计数,和到目前为止的平均值。 它迭代所有对象,汇总工资,计算有多少,并计算每次迭代的平均值。 最终它返回该对象(累加器)并读取平均属性。

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

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

var people = [{
  name: 'john',
  job: 'manager',
  salary: 2000
},
  {
  name: 'sam',
  job: 'manager',
  salary: 6000
},
  {
  name: 'frodo',
  job: 'janitor'
}];
function average(acc, ele, index) {
    return (acc + ele) / (index + 1);
}

var result = _.chain(people)
    .filter('job', 'manager')
    .map('salary')
    .reduce( average )
    .value();

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

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

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

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

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

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

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

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

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

console.log(avg(people))

您要做的是 1. 获取所有对象的“经理”类型 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))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM