[英]Using Lodash or vanilla JS what is the most efficient way to filter an array based on object keys?
[英]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,也不使用任何库,也不使用任何filter
、 reduce
方法。 改用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.