lodash: mappage d'un tableau à un objet

90

Existe-t-il une fonction lodash intégrée pour prendre ceci:

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

Et sortez ceci:

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

En ce moment, j'utilise juste 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');

Vous vous demandez s'il existe un raccourci lodash.

coeur
la source

Réponses:

132

Une autre façon avec lodash 4.17.2

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

ou

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

ou avec _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)
stasovlas
la source
@Akrikos the _.keyBytransformera le tableau entier en objet, alors que la question est principalement d'avoir un élément de chaque objet dans le tableau comme clé et un autre élément comme valeur. Si _.keyByest utilisé, toutes les valeurs seront des objets.
Mustafa Ehsan Alokozay
Merci @MustafaEhsanAlokozay Vous avez raison, cette réponse ne fait pas exactement ce qu'il faut. Je supprimerai mon commentaire car il n'est pas utile. Cela peut rendre votre commentaire étrange, mais mieux vaut que mon commentaire incorrect reste plus longtemps.
Akrikos
53

Vous devriez utiliser _.keyBy pour convertir facilement un tableau en objet.

Docs ici

Exemple d'utilisation ci-dessous:

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>

Si nécessaire, vous pouvez manipuler le tableau avant d'utiliser _.keyBy ou l'objet après avoir utilisé _.keyBy pour obtenir le résultat exact souhaité.

danday74
la source
2
Regardez d'abord ceci pour comprendre la réponse la plus votée par stasovlas.
Roman Susi
3
C'est une bonne réponse, mais elle ne répond PAS à la question. Les valeurs doivent être des chaînes et non des objets.
Dem Pilafian
34

Oui, c'est ici , en utilisant_.reduce

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

_.reduce(params , function(obj,param) {
 obj[param.name] = param.input
 return obj;
}, {});
Jagdish Idhate
la source
Encore une fois, se reduce()précipite avec un autre cas d'utilisation. Façon intelligente de le faire!
Dan
Quelqu'un a-t-il la version dactylographiée de ceci?
mr.bjerre le
La réalité est qu'il est mathématiquement vrai que vous pouvez implémenter littéralement n'importe quelle action d'itération en utilisant réduire / injecter, car la réduction est isomorphe à une liste. Cependant, cette flexibilité a un prix en termes de lisibilité. N'utilisez pas à _.reducemoins que cela n'exprime avec précision ce que vous essayez de faire: cela obscurcit considérablement le point du code dans tous les autres cas. _.zipObjectPersonnellement, je préfère la solution de @djechlin - à défaut, l' approche _.keyBy/ _.mapValues.
Robert Fischer
15

Cela semble être un travail pour Object.assign:

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

Édité pour envelopper comme une fonction similaire à OP, ce serait:

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

(Merci à Ben Steward, bonne réflexion ...)

PleuvoirColonie
la source
Peut-être envelopper cela dans une fonction parent afin que l'utilisateur puisse déterminer quelles clés seraient utilisées en les passant, comme l'OP l'avait fait.
Ben Steward
11

Vous pouvez utiliser un javascript de ligne avec la méthode de réduction de tableau et la déstructuration ES6 pour convertir un tableau de paires clé / valeur en objet.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Faisal Hasnain
la source
3
Malheureusement, c'est O (n ^ 2).
jimrandomh
10

C'est probablement plus verbeux que vous ne le souhaitez, mais vous demandez une opération légèrement complexe afin que le code réel puisse être impliqué (l'horreur).

Ma recommandation, avec zipObjectc'est assez logique:

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

Une autre option, plus hacky, utilisant fromPairs:

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

La fonction anonyme montre le piratage - je ne crois pas que JS garantit l'ordre des éléments dans l'itération des objets, donc l'appel .values()ne fera pas l'affaire.

Djechlin
la source
Je ne vois rien de piraté à utiliser fromPairs, et les appels ne values()suffiront pas. Au moins du point de vue de la lisibilité.
x-yuri
6

Une autre façon avec lodash

créer des paires, puis soit construire un objet, soit ES6 Mapfacilement

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

ou

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

Voici un exemple de travail

Koushik Chatterjee
la source
1
La bonne partie de cette solution est qu'elle est également réalisable en plaine ES:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante
@fregante, Chrome 73+ uniquement caniuse.com/?search=fromEntries
d9k
6

Il peut également résoudre sans utiliser aucune fonction lodash comme celle-ci:

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

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


console.log(output);

entrez la description de l'image ici

Zeeshan Afzal Satti
la source