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

时间:2015-01-29 11:13:44

标签: javascript underscore.js 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 });

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

8 个答案:

答案 0 :(得分:29)

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

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

let average = _.meanBy(people, (p) => p.budget);

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

答案 1 :(得分:20)

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

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

fast 解决方案是不使用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;

我认为在大多数情况下,客户端开发可读性性能更重要,所以我认为第一个变体是最有效的&#34;。

答案 2 :(得分:3)

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

这会将对象传递给 reduce ,因为 accumulator 具有三个属性:工资总和,工资计数和目前的平均值。它迭代所有对象,对工资求和,计算有多少,并计算每次迭代的平均值。最终它返回该对象(累加器)并读取 average 属性。

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

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

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

答案 3 :(得分:3)

lodash v3:

_.sum(people, 'salary') / people.lengthpeople必须为空)

lodash v4:

_.meanBy(people, 'salary')

答案 4 :(得分:1)

function average(acc, ele, index) {
    return (acc + ele) / (index + 1);
}

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

答案 5 :(得分:1)

使用功能更强大的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);

答案 6 :(得分:0)

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

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

它需要项目的总和并将其与项目数量相除,这几乎是平均值的定义。

太糟糕了,如果你想让它整齐一行,代码就会变得不那么清晰了。

答案 7 :(得分:0)

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

@   IN  NS  ns1.blublublu.com. //Saying there is a nameserver at ns1.blublublu.com
@   IN  NS  ns2.blublublu.com.
@   IN  A   192.168.100.13 //static if of the domain blublublu.com
@   IN  AAAA    ::1
ns1  IN  A   192.168.100.13 //subdomain of ns1.blublublu.com
ns2  IN  A   192.168.100.14 //subdomain of ns2.blublublu.com, if is the same computer (not ideal) then it would be the same ip

你做的是什么 1.获取所有对象&#39;经理&#39;类型 2.提取工资&#39;他们的财产/领域 3.使用均值函数求平均值

以下是为方便起见的完整版代码,可在nodejs上运行。

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

console.log(avg(people))
相关问题