2015-06-12 4 views
18

Sto cercando di utilizzare la funzione underscore.js _.map su una matrice di oggetti, per ottenere una matrice con una proprietà di ciascun oggetto. Questo è lo scenario consueto, in modo da:Funzione Underscore.js _.map: salta un valore

var finalArray = _.map(myArray, function(obj) { 
    return obj.myProperty; 
}); 

Ma in alcuni casi ho bisogno che nulla essere aggiunto nella matrice. Potrebbe essere qualcosa di simile:

var finalArray = _.map(myArray, function(obj) { 
    if (!obj.ignore) { 
     return obj.myProperty; 
    } 
}); 

Il risultato di ciò è che un valore undefined viene spinto nella matrice, che non è la stessa non spingere nulla.

C'è un modo per la funzione della mappa di non premere un valore, o ho bisogno di post-elaborare il mio finalArray per rimuovere i undefined indesiderati?

+0

Penso che dovresti considerare di scegliere come risposta migliore quella di Thomas Eschemann, perché attraversa tutti gli elementi della matrice una sola volta come richiesto in "C'è un modo per la funzione della mappa di non spingere un valore", l'obiettivo principale per questa domanda. E la risposta è usare reduce() invece di map(). –

+0

La risposta attualmente scelta è per la seconda parte della domanda "Devo post-processare il mio finalArray per rimuovere gli indefiniti indesiderati?". E la risposta alla seconda parte è: No, non è necessario post-processare finalArray(), è necessario usare reduce() invece di map() per evitare la post-elaborazione. –

risposta

22

si dovrebbe usare _.filter() prima _.map()

var filteredArray = _.filter(myArray,function(obj) { 
    return !obj.ignore; 
}); 

var finalArray = _.map(filteredArray, function(obj) { 
    return obj.myProperty; 
}); 
+0

** dopo **, non _prima_ – hindmost

+5

come foucdeg descrive il suo problema, non è necessario trasformare gli input per decidere se debbano essere esclusi o meno. filtro ** prima ** è quindi migliore in termini di prestazioni – couettos

+0

@hindmost Entrambi funzionano però. – foucdeg

1

Quindi questo significa che si desidera filtrare, quindi mappare l'array.

di fare questo in modo underscore, è necessario per passare il tuo array in questo gasdotto:

myArray ->Filtro ->mappa -> finalArray

var isIncluded = function(obj){ 
    return !obj.ignore 
} 
var takeProperty = function(obj){ 
    return obj.myProperty 
} 
var finalArray = _.map(_.filter(myArray, isIncluded), takeProperty ); 
+1

** NOTA ** È possibile sostituire 'takeProperty' con la funzione' _.pluck' come @ dev-null proposto in un'altra risposta. –

+0

@foucdeg Underscore ti fa pensare in unità più piccole anziché in * una funzione fat che include più processi *. Siete incoraggiati a scrivere una piccola unità di funzione, unitevi a loro in operazioni sequenziali per creare un'unità di elaborazione più grande. –

4

.map mapperà un nuovo valore per l'array, è possibile utilizzare .filter per filtrare l'array. FYI è possibile utilizzare .pluck per mappare una proprietà da un oggetto:

_.chain(myArray).filter(function(obj) { return !obj.ignore; }).pluck('myProperty').value(); 

È anche possibile utilizzare .where come questo:

_.chain(myArray).where({ignore: false}).pluck('myProperty').value(); 

Oppure:

_.pluck(_.where(myArray, {ignore: false}), 'myProperty'); 
16

Si potrebbe utilizzare ridurre:

myArray.reduce(function (acc, obj) { 
    if (!obj.ignore) { 
     acc.push(obj.myProperty); 
    } 
    return acc; 
}, []); 

o con lodash:

_.reduce(myArray, function (acc, obj) { 
    if (!obj.ignore) { 
    acc.push(obj.myProperty); 
    } 
    return acc; 
}, []); 
+3

Penso che questa sia la risposta migliore, perché scorre tutti gli elementi una sola volta come richiesto da @foucdeg "C'è un modo per la funzione mappa di non premere un valore". La risposta è usare reduce() invece di map(). –

12

Questo può essere fatto con metodi di sottolineatura da solo, points-free style:

var finalArray = _.chain(myArray) 
    .reject('ignore') 
    .pluck('myProperty') 
    .value(); 
+1

Adoro questo approccio. È semplicemente pulito e molto leggibile. (Anche * puro funzionale, pensiero monadico *) –

+3

@Pavlo Hai bisogno di un esplicito '.chain' con Underscore e puoi semplicemente usare' .reject ('ignore') 'invece di' .reject (_. Property ('ignore')) '. http://jsfiddle.net/nikoshr/2gpvws1u/ – nikoshr

0

Ecco un altro modo. Questo usa la funzione di composizione in underscore. Perché comporre? la composizione è supportata dalla teoria delle categorie in matematica. In questo modo è anche point-free.

var pluckMyProp = function(array) { 
    return _.pluck(array, 'myProperty') 
} 

var reject = function(array) { 
    return _.reject(array, function(element) { 
     return element['ignore'] === true 
    }) 
} 

var finalArray = _.compose(pluckMyProp, reject) 
var data = [{myProperty: 1, ignore: false}, {ignore: true}, {myProperty: 2}] 


finalArray(data) //=> [1,2] 
+0

Per convertire il precedente da underscore a lodash, cambia '_.pluck' in' _map' e '_.compose' in' _.flowRight'. – mrienstra

2

Provare a utilizzare di lodash compact(). Crea una matrice con tutti i valori falsi rimossi.Pertanto, vengono rimossi i valori false, null, 0, "", undefined e NaN.

https://lodash.com/docs#compact

sto usando-è molto pulito.