2012-05-02 5 views
52

Sto utilizzando l'eccellente libreria Underscore.js. Ho un compito specifico che posso fare bene usando JavaScript o jQuery, ma mi chiedevo se ci fosse una sorta di astrazione disponibile in Underscore che mi stavo perdendo.Underscore.js: crea una mappa dall'elenco degli oggetti utilizzando una chiave trovata nell'oggetto

Essenzialmente Ho un oggetto in questo modo -

var some_object_array = [{id: "a", val: 55}, {id: "b", val: 1}, {id: "c", val: 45}]; 

voglio convertire questo in -

var some_map = {"a": {id: "a", val: 55}, "b": {id: "b", val: 1}, "c": {id: "c", val: 45}}; 

So che posso usare _.groupBy(some_object_array, "id"). Ma questo restituisce una mappa come questa -

var some_grouped_map = {"a": [{id: "a", val: 55}], "b": [{id: "b", val: 1}], "c": [{id: "c", val: 45}]}; 

Si noti che questo fa ciò che è pubblicizzato da fare. Ma speravo di ottenere some_map senza iterare sugli oggetti da solo.

Qualsiasi aiuto apprezzato.

risposta

80

FWIW dal underscore.js è ora possibile utilizzare _.object()

var some_map = _.object(_.map(some_object_array, function(item) { 
    return [item.id, item] 
})); 
+7

è * così * utile che definisco sempre 'mapo = _.compose (_. Object, _.map);' –

+0

Sembra che '_.object()' sia stato rimosso. È un'alternativa a questo ancora disponibile in underscore? –

+1

Correggimi se sbaglio, ma penso che con lodash potresti anche usare la singola funzione '_.transform'. – emkman

12

Non penso ci sia qualcosa di più vicino di groupBy per le tue esigenze. Anche se ci fosse, non sarebbe fare meglio di un semplice:

var some_map = {}; 
_.each(some_object_array, function(val) { 
    some_map[val.id] = val; 
}); 
+0

Ok, questo è quello che ho fatto alla fine. Ma era curioso di sapere se c'era un modo migliore per farlo. – Chantz

+0

+1 perché trovo questo approccio più semplice di '_.object (_. Map (...))' –

+0

è il tipo di concatenamento per '_.chain (data) .map ((val) => [val. id, val]). object(). value() ' – svarog

30

C'è anche questo metodo

_.reduce(data, function (o, item) { o[item.key] = item.value; return o }, {}) 

Quale è una dichiarazione con due affermazioni nella funzione interna.

+1

non dovresti usare riduci poichè è usato per scopi diversi (riduci un elenco di valori in un singolo valore), in pratica si tratta di un hack, che conduce un sacco di confusione per altri sviluppatori che leggono il tuo codice ... – user2846569

+5

@ user2846569 riassume un elenco in un singolo oggetto. Perfettamente l'applicazione di 'ridurre'. –

+0

@OttoAllmendinger Tuttavia, l'operazione di riduzione specificata utilizza argomenti eterogenei, che non sono convenzionali. In una funzione di riduzione convenzionale, vuoi che i tuoi 'a' e' b' (qui 'o' e' item') siano dello stesso tipo. In effetti, le lingue fortemente tipizzate non consentirebbero una tale funzione di riduzione come mostrato qui. La mappatura degli oggetti su – Milosz

40

per il vostro caso, è necessario utilizzare la funzione indexBy:

var some_object_array = [{id: "a", val: 55}, {id: "b", val: 1}, {id: "c", val: 45}]; 

var some_grouped_map = _.indexBy(some_object_array, 'id'); 
+0

risposta più appropriata per il caso – user2846569

+0

Concordato, questa dovrebbe essere la risposta accettata. –

+0

Questa è la risposta. –

3

I questo caso non c'è bisogno di iterare il array. Non map, non reduce, non transform. Tutto ciò che serve è il vecchio pluck

_.object(_.pluck(some_object_array, 'id'), some_object_array); 
2

per ES6, è

var some_map = _.chain(some_object_array) 
       .map(item => [item.id, item]) 
       .object() 
       .value()