web-dev-qa-db-ja.com

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

しかし、これが正しいアプローチかどうかはわかりません。

21
meajmal

ここですべての人が複雑になりすぎるのはなぜですか?

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

「効率的」とは非常に曖昧な用語です。 「効率的」と言えば、パフォーマンス、または読みやすさ、または簡潔さなどについて考えることができます。ほとんどの読み取り可能簡潔の解決策は:

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

クライアント側の開発では、ほとんどの場合、readabilityperformanceよりも重要であると思うので、最初のバリアントが最も「効率的」だと思います。

20
alexpods

lodash v3:

_.sum(people, 'salary') / people.lengthpeopleは空にできません)

lodash v4:

_.meanBy(people, 'salary')

5
Stalinko

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

これは、オブジェクトをreduceaccumulatorとして渡します。これは、給与の合計、給与の数、およびこれまでの平均の3つのプロパティを持ちます。すべてのオブジェクトを反復処理し、給与を合計し、存在する数を数え、各反復で平均を計算します。最終的に、そのオブジェクト(accumulator)を返し、averageプロパティが読み取られます。

単一の組み込みメソッドの呼び出しは、4つのネイティブ関数の呼び出しよりも高速(つまり効率的)である必要があります。 「エレガント」は見る人の目にあります。 ;-)

ところで、オブジェクトリテラルにエラーがあります。

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

より機能的なlodashバージョン(lodash-fp)およびes2015矢印関数と自動カレーを使用して、より柔軟で機能的なフレーバーソリューションを取得できます。

あなたはそれをい1つのライナーに入れることができます:

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);
1
AA.
function average(acc, ele, index) {
    return (acc + ele) / (index + 1);
}

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

私が考えることができる最もきれいな(エレガントな)方法は次のとおりでした:

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

アイテムの合計を取り、アイテムの数で割ります。これはほとんど平均の定義です。

残念なことに、それを1ライナーにすっきりさせたい場合は、コードが読みにくくなります。

0
Mikael Lepistö

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))
0
Vlad Bezden