2015-01-29 10 views
10

ich ein Array von Objekten, ist die Anzahl der Objekte variabel -effizienteste Weg Durchschnitt finden lodash mit

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

Was ist der eleganteste Weg, um den Durchschnitt der Gehälter aller Manager lodash mit finden? (Ich gehe davon aus uns überprüfen, ob ein Objekt-Manager ist, als auch wenn das Objekt ein Gehalt Eigenschaft)

Ich wurde in den folgenden Zeilen zu denken -

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

Aber ich bin nicht sicher, ob dies ist der richtige Ansatz.

+0

Ist das Code funktioniert? Die Kürzung scheint nicht avg zu finden, sondern gibt eine Summe aller Gehälter zurück. –

Antwort

20

"effizient" ist sehr zweideutigen Begriff. Wenn Sie "effizient" sagen, können Sie über Leistung oder Lesbarkeit oder Prägnanz und so weiter nachdenken. Ich denke, die meisten lesbar und prägnante Lösung ist:

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

Die schnell Lösung nicht verwenden loadash ist, noch eine Bibliothek, noch irgendwelche filter, reduce Methoden überhaupt. Verwenden Sie for Schleife statt:

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; 

Ich denke, für die Client-Seite Entwicklung Lesbarkeit ist wichtiger als Leistung in den meisten Fällen, so denke ich, erste Variante ist sehr „effizient“.

+0

anders als der klare Fehler in der Reduzierung, die es die Summe und nicht der Durchschnitt in der OP-Frage zurückgibt, wie unterscheidet sich das von seiner Lösung? (wirklich fragen, keine Kritik beabsichtigt) – lascort

+0

'a + m.saray/p.length' - betrachten Sie die' p.length' - das Ergebnis Durchschnitt, nicht Summe. – alexpods

+0

@lascort Du kannst es selbst ausprobieren, wenn du mir nicht glaubst. Gehe zu [lodash] (https://lodash.com/docs), öffne die Konsole, erstelle das 'people'-Array und kopiere dann meine Lösung. – alexpods

3

Ich weiß nicht, über lowdash, aber vielleicht eine einfache JS-Lösung erhalten Sie dort helfen:

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 

Dies geht ein Objekt als Akkumulator reduzieren die drei Eigenschaften aufweist: die Summe der Gehälter, die Anzahl der Gehälter und der Durchschnitt bisher. Es iteriert über alle Objekte, summiert die Gehälter, zählt wie viele es gibt und berechnet den Durchschnitt bei jeder Iteration. Schließlich gibt es das Objekt zurück (Akkumulator) und die durchschnittliche Eigenschaft wird gelesen.

Der Aufruf einer einzelnen integrierten Methode sollte schneller (d. H. Effizienter) sein als der Aufruf von 4 nativen Funktionen. "Elegant" liegt im Auge des Betrachters. ;-)

BTW, gibt es Fehler im Objektliteral, sollte es sein:

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

meisten sauber (elegant) Weg, ich denken konnte, war:

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

Es dauert Summe von Elementen und teilt es mit der Anzahl der Elemente, die so ziemlich die Definition von Durchschnitt ist.

Schade, dass wenn Sie möchten, dass es zu einem ordentlichen Einzeiler, der Code wird weniger klar zu lesen.

1
function average(acc, ele, index) { 
    return (acc + ele)/(index + 1); 
} 

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

Mit funktioneller lodash Version (lodash-fp) und es2015 Sie können Pfeil Funktionen und Auto-Curry verwenden, um eine flexiblere und funktionelle aromatisierte Lösung zu erhalten.

Sie können es in einem hässlichen Motto setzen:

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

Oder Sie können eine ordentliche DSL erstellen:

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

lodash/fp Verwendung und ES2016/ES6 es in einem funktionalen getan werden kann,

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

console.log(avg(people)) 

Was Sie tun, ist 1. alle 'Manager' Objekte Get Typ 2. Extrahieren Sie 'Gehalt' Eigenschaft/Feld von ihnen 3. Suchen Sie Durchschnitt mit Mittelwertfunktion

Hier ist eine vollständige Version von Code für Ihre Bequemlichkeit, die auf Nodejs ausgeführt wird.

'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)) 
13

Warum alle Menschen hier zu kompliziert werden?

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

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

sich nach den docs: https://lodash.com/docs/#meanBy

+1

Kann vereinfacht werden, um 'lay average = _.meanBy (people,' budget '); '. Funktioniert auch nur für v4. * – Stalinko

0

lodash v3:

_.sum(people, 'salary')/people.length (people darf nicht leer sein)

lodash v4:

_.meanBy(people, 'salary')

Verwandte Themen