lodash: mappatura array su oggetto


93

C'è una funzione lodash incorporata per prendere questo:

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];

E invia questo:

var output = {
    foo: 'bar',
    baz: 'zle'
};

In questo momento sto solo usando Array.prototype.reduce():

function toHash(array, keyName, valueName) {
    return array.reduce(function(dictionary, next) {
        dictionary[next[keyName]] = next[valueName];
        return dictionary;
    }, {});
}

toHash(params, 'name', 'input');

Mi chiedo se ci sia una scorciatoia lodash.

Risposte:


138

Un altro modo con lodash 4.17.2

_.chain(params)
    .keyBy('name')
    .mapValues('input')
    .value();

o

_.mapValues(_.keyBy(params, 'name'), 'input')

o con _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)

@Akrikos _.keyBytrasformerà l'intero array in un oggetto, mentre la domanda è principalmente sull'avere un elemento da ogni oggetto nell'array come chiave e un altro elemento come valore. Se _.keyByviene utilizzato, tutti i valori saranno oggetti.
Mustafa Ehsan Alokozay

Grazie @MustafaEhsanAlokozay Hai ragione, quella risposta non fa esattamente la cosa giusta. Eliminerò il mio commento perché non è utile. Ciò potrebbe rendere strano il tuo commento, ma è meglio che rimanga più a lungo il mio commento errato.
Akrikos

55

Dovresti usare _.keyBy per convertire facilmente un array in un oggetto.

Documenti qui

Esempio di utilizzo di seguito:

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];
console.log(_.keyBy(params, 'name'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>

Se necessario, è possibile manipolare l'array prima di utilizzare _.keyBy o l'oggetto dopo aver utilizzato _.keyBy per ottenere il risultato esatto desiderato.


2
Guarda prima questo per capire la risposta più votata di stasovlas.
Roman Susi

5
Questa è una bella risposta, ma NON risponde alla domanda. I valori dovrebbero essere stringhe non oggetti.
Dem Pilafian

34

Sì, è qui , usando_.reduce

var params = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];

_.reduce(params , function(obj,param) {
 obj[param.name] = param.input
 return obj;
}, {});

Ancora una volta reduce()piomba con un altro caso d'uso. Modo intelligente per farlo!
Dan

Qualcuno ha la versione scritta a macchina di questo?
mr.bjerre

La realtà è che è matematicamente vero che puoi implementare letteralmente qualsiasi azione di iterazione usando reduce / inject, poiché reduce è isomorfo a un elenco. Tuttavia, tale flessibilità ha un prezzo in termini di leggibilità. Non usare a _.reducemeno che ciò non esprima accuratamente ciò che stai cercando di fare: oscura in modo significativo il punto del codice in qualsiasi altro caso. Personalmente preferisco la _.zipObjectsoluzione di @djechlin: in caso contrario, l' approccio _.keyBy/ _.mapValues.
Robert Fischer

16

Sembra un lavoro per Object.assign:

const output = Object.assign({}, ...params.map(p => ({[p.name]: p.input})));

Modificato per avvolgere come una funzione simile agli OP, questo sarebbe:

const toHash = (array, keyName, valueName) => 
    Object.assign({}, ...array.map(o => ({[o[keyName]]: o[valueName]})));

(Grazie a Ben Steward, buona idea ...)


Magari inseriscilo in una funzione genitore in modo che l'utente possa determinare quali tasti sarebbero stati usati passandoli, come aveva fatto l'OP.
Ben Steward


10

Questo è probabilmente più dettagliato di quanto desideri, ma stai chiedendo un'operazione leggermente complessa, quindi potrebbe essere coinvolto il codice effettivo (l'orrore).

La mia raccomandazione, con zipObjectquesto è abbastanza logico:

_.zipObject(_.map(params, 'name'), _.map(params, 'input'));

Un'altra opzione, più hacky, usando fromPairs:

_.fromPairs(_.map(params, function(val) { return [val['name'], val['input']));

La funzione anonima mostra l'hackiness: non credo che JS garantisca l'ordine degli elementi nell'iterazione degli oggetti, quindi il callling .values()non lo farà.


Non vedo nulla di hacky sull'utilizzo fromPairs, e la chiamata in values()effetti non va bene. Almeno dal punto di vista della leggibilità.
x-yuri

6

Un altro modo con lodash

creare coppie e quindi costruire un oggetto o ES6 Mapfacilmente

_(params).map(v=>[v.name, v.input]).fromPairs().value()

o

_.fromPairs(params.map(v=>[v.name, v.input]))

Ecco un esempio funzionante


1
La parte buona di questa soluzione è che è fattibile anche in pianura ES:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante

@fregante, Chrome 73+ only caniuse.com/?search=fromEntries
d9k

6

Può anche risolvere senza utilizzare alcuna funzione lodash come questa:

let paramsVal = [
    { name: 'foo', input: 'bar' },
    { name: 'baz', input: 'zle' }
];
let output = {};

paramsVal.forEach(({name, input})=>{
  output[name] = input;
})


console.log(output);

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.