简体   繁体   English

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

[英]most efficient way to find average using lodash

I have an array of objects, the number of objects is variable -我有一个对象数组,对象的数量是可变的 -

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

Whats the most elegant way to find the average of the salaries of all managers using lodash?使用 lodash 找到所有经理的平均工资的最优雅的方法是什么? ( I assume we have to check if an object is manager, as well as if the object has a salary property) (我假设我们必须检查一个对象是否是经理,以及该对象是否具有工资属性)

I was thinking in the below lines -我在想以下几行 -

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

But I am not sure if this is the right approach.但我不确定这是否是正确的方法。

Why all people gets over-complicated here?为什么所有人都在这里变得过于复杂?

 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>

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

"efficient" is very ambiguous term. “高效”是一个非常含糊的词。 Saying "efficient" you can think about performance , or readability , or conciseness and so on.说“高效”,您可以考虑性能可读性简洁性等。 I think the most readable and concise solution is:我认为最易读简洁的解决方案是:

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

The most fast solution is do not use loadash, nor any library, nor any filter , reduce methods at all.快速的解决方案是根本不使用 loadash,也不使用任何库,也不使用任何filterreduce方法。 Use for loop instead:改用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;

I think for the client side development readability is more important than performance in most cases , so I think first variant is most "efficient".我认为对于客户端开发而言,在大多数情况下可读性性能更重要,所以我认为第一个变体是最“有效”的。

lodash v3: lodash v3:

_.sum(people, 'salary') / people.length ( people mustn't be empty) _.sum(people, 'salary') / people.length ( people不能为空)

lodash v4: lodash v4:

_.meanBy(people, 'salary')

I don't know about lowdash, but maybe a plain JS solution will help you get there:我不知道 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

This passes an object to reduce as the accumulator that has three properties: the sum of salaries, the count of salaries, and the average so far.此传递一个目的是减少作为具有三个属性累加器:薪金的总和,薪水的计数,和到目前为止的平均值。 It iterates over all the objects, summing the salaries, counting how many there are and calculating the average on each iteration.它迭代所有对象,汇总工资,计算有多少,并计算每次迭代的平均值。 Eventually it returns that object (the accumulator ) and the average property is read.最终它返回该对象(累加器)并读取平均属性。

Calling a single built–in method should be faster (ie more efficient) than calling 4 native functions.调用单个内置方法应该比调用 4 个本机函数更快(即更有效)。 "Elegant" is in the eye of the beholder. “优雅”在旁观者的眼中。 ;-) ;-)

BTW, there are errors in the object literal, it should be:顺便说一句,对象文字中有错误,应该是:

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

With the more functional lodash version ( lodash-fp ) and es2015 you can to use arrow functions and auto curry to get a more flexible and functional flavored solution.使用功能更强大的lodash版本 ( lodash-fp ) 和es2015您可以使用箭头函数和自动咖喱来获得更灵活和功能性的解决方案。

You can put it in an ugly one liner:你可以把它放在一个丑陋的单衬里:

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

Or you can create a tidy DSL:或者你可以创建一个整洁的 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);

Most clean (elegant) way I could think of was:我能想到的最干净(优雅)的方式是:

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

It takes sum of items and divides its with number of items, which is pretty much the definition of average.它取项目的总和并将其除以项目的数量,这几乎是平均值的定义。

Too bad that if you would like to make that to neat one-liner, the code will get less clear to read.太糟糕了,如果你想把它变成整洁的单行代码,代码会变得不太清晰。

Using lodash/fp and ES2016/ES6 it can be done in a more functional way使用lodash/fp和 ES2016/ES6 可以以更实用的方式完成

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

console.log(avg(people))

What you do is 1. Get all objects 'manager' type 2. Extract 'salary' property/field from them 3. Find average using mean function您要做的是 1. 获取所有对象的“经理”类型 2. 从中提取“薪水”属性/字段 3. 使用均值函数求平均值

Here is a full version of code for your convenience that runs on nodejs.为方便起见,这是在 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