web-dev-qa-db-fra.com

le moyen le plus efficace de trouver la moyenne en utilisant lodash

J'ai un tableau d'objets, le nombre d'objets est variable - 

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

Quel est le moyen le plus élégant de trouver la moyenne des salaires de tous les managers utilisant lodash? (Je suppose que nous devons vérifier si un objet est responsable, ainsi que si l'objet a une propriété de salaire)

Je pensais dans les lignes ci-dessous - 

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

Mais je ne suis pas sûr que ce soit la bonne approche.

16
meajmal

Pourquoi tout le monde devient trop compliqué ici?

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

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

Selon les documents: https://lodash.com/docs/#meanBy

"efficace" est un terme très ambigu. En disant "efficace", vous pouvez penser à performance, ou lisibilité, ou concision, etc. Je pense que la solution la plus lisible lisible et concise est:

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

La solution la plus fast consiste à ne pas utiliser loadash, ni aucune bibliothèque, ni aucune méthode filter, reduce. Utilisez plutôt la boucle 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;

Je pense que pour le développement côté client, lisibilité est plus important que performance dans la plupart des cas, je pense donc que la première variante est la plus "efficace".

20
alexpods

Je ne sais pas à propos de lowdash, mais peut-être qu'une solution simple de JS vous aidera à y arriver:

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

Cela transmet un objet à réduire sous la forme accumulateur ayant trois propriétés: la somme des salaires, le nombre de salaires et la moyenne jusqu'à présent. Il parcourt tous les objets, en additionnant les salaires, en en calculant le nombre et en calculant la moyenne à chaque itération. Finalement, il retourne cet objet (le accumulator) et la propriété average est lue.

L’appel d’une seule méthode intégrée devrait être plus rapide (c’est-à-dire plus efficace) que l’appel de 4 fonctions natives. "Elegant" est dans l'oeil du spectateur. ;-)

BTW, il y a des erreurs dans le littéral d'objet, il devrait être:

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

Avec les versions lodash (lodash-fp) et es2015 plus fonctionnelles, vous pouvez utiliser les fonctions fléchées et curry automatique pour obtenir une solution aromatisée plus souple et plus fonctionnelle.

Vous pouvez le mettre dans un vilain liner:

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

Ou vous pouvez créer un DSL bien rangé:

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

Le moyen le plus propre (élégant) auquel je pouvais penser était:

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

Il prend la somme des articles et divise son avec le nombre d'articles, ce qui est à peu près la définition de la moyenne. 

Dommage que si vous souhaitez que cela devienne une ligne, le code sera moins lisible.

0
Mikael Lepistö

En utilisant lodash/fp et ES2016/ES6, cela peut être fait de manière plus fonctionnelle

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

console.log(avg(people))

Ce que vous faites est 1. Récupère le type de gestionnaire de tous les objets 2. Extrayez-leur la propriété/le champ 'salaire' 3. Trouver la moyenne en utilisant la fonction moyenne

Voici une version complète du code pour votre commodité qui fonctionne sur 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