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.

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 }),
    {}
)

@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é.


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;
}, {});

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 ...)


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


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.


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


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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.