Наиболее эффективный способ поиска среднего уровня использования 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 });
Но я не уверен, что это правильный подход.
Ответы
Ответ 1
"эффективный" - очень двусмысленный термин. Говоря "эффективно", вы можете думать о производительности, читаемости или краткости и т.д. Я думаю, что наиболее читаемым и лаконичным решением является:
_(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;
Я думаю, что для чтения на стороне клиента читаемость важнее производительности в большинстве случаев, поэтому я считаю, что первый вариант наиболее эффективен.
Ответ 2
Почему все люди переусердствуют здесь?
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
Ответ 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
Это передает объект для уменьшения как аккумулятора, который имеет три свойства: сумму зарплат, количество зарплат и среднее значение. Он выполняет итерацию по всем объектам, суммируя зарплаты, подсчитывая, сколько их есть и вычисляет среднее значение на каждой итерации. В конце концов он возвращает этот объект (аккумулятор) и считывает среднее свойство.
Вызов одного встроенного метода должен быть более быстрым (то есть более эффективным), чем вызов 4 собственных функций. "Элегантный" находится в глазах смотрящего.; -)
Кстати, в объектном литерале есть ошибки, это должно быть:
var people = [{
name: 'john',
job: 'manager',
salary: 2000
},
{
name: 'sam',
job: 'manager',
salary: 6000
},
{
name: 'frodo',
job: 'janitor'
}];
Ответ 4
function average(acc, ele, index) {
return (acc + ele) / (index + 1);
}
var result = _.chain(people)
.filter('job', 'manager')
.map('salary')
.reduce( average )
.value();
Ответ 5
С более функциональной версией 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
Самый чистый (элегантный) способ, о котором я мог думать, был:
var salariesOfManagers = _(people).filter({job: 'manager'}).filter('salary').pluck('salary');
var averageSalary = salariesOfManagers.sum() / salariesOfManagers.value().length;
Требуется сумма элементов и делит ее на количество элементов, что в значительной степени определяется средним значением.
Слишком плохо, что если вы хотите сделать это аккуратным однострочным, код станет менее понятным для чтения.
Ответ 7
Используя lodash/fp и ES2016/ES6, это можно сделать более функциональным способом
const avg = flow(
filter({job: 'manager'}),
map('salary'),
mean
)
console.log(avg(people))
Что вы делаете
1. Получить тип всех менеджеров объектов
2. Извлеките из них свойство/поле "заработная плата"
3. Найти среднее значение с помощью средней функции
Вот полная версия кода для вашего удобства, которая выполняется на узлах.
'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))
Ответ 8
lodash v3:
_.sum(people, 'salary') / people.length
(people
не должно быть пустым)
lodash v4:
_.meanBy(people, 'salary')