lodash: mapeo de matriz a objeto

90

¿Hay una función lodash incorporada para tomar esto?

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

Y da salida a esto:

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

En este momento solo estoy 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');

Me pregunto si hay un atajo pesado.

núcleo
fuente

Respuestas:

132

Otra forma 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 }),
    {}
)
Stasovlas
fuente
@Akrikos _.keyBytransformará toda la matriz en un objeto, mientras que la pregunta se trata principalmente de tener un elemento de cada objeto en la matriz como clave y otro elemento como valor. Si _.keyByse usa, todos los valores serán objetos.
Mustafa Ehsan Alokozay
Gracias @MustafaEhsanAlokozay Tienes razón, esa respuesta no hace exactamente lo correcto. Eliminaré mi comentario porque no es útil. Eso puede hacer que tu comentario se vea extraño, pero es mejor que mi comentario incorrecto permanezca por más tiempo.
Akrikos
53

Debería utilizar _.keyBy para convertir fácilmente una matriz en un objeto.

Documentos aquí

Ejemplo de uso a continuación:

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 es necesario, puede manipular la matriz antes de usar _.keyBy o el objeto después de usar _.keyBy para obtener el resultado exacto deseado.

danday74
fuente
2
Mire primero esto para comprender la respuesta más votada por stasovlas.
Roman Susi
3
Esta es una buena respuesta, pero NO responde a la pregunta. Los valores deben ser cadenas, no objetos.
Dem Pilafian
34

Sí, está aquí , usando_.reduce

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

_.reduce(params , function(obj,param) {
 obj[param.name] = param.input
 return obj;
}, {});
Idhate de Jagdish
fuente
Una vez más, reduce()aparece otro caso de uso. ¡Manera inteligente de hacerlo!
Dan
¿Alguien tiene la versión mecanografiada de esto?
mr.bjerre
La realidad es que es matemáticamente cierto que puede implementar literalmente cualquier acción de iteración usando reducir / inyectar, ya que reducir es isomorfo a una lista. Sin embargo, esa flexibilidad tiene un precio en legibilidad. No lo use a _.reducemenos que exprese con precisión lo que está tratando de hacer: oscurece significativamente el punto del código en cualquier otro caso. Personalmente prefiero la _.zipObjectsolución de @djechlin; de lo contrario, el enfoque _.keyBy/ _.mapValues.
Robert Fischer
15

Esto parece un trabajo para Object.assign:

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

Editado para envolver como una función similar a los OP, esto sería:

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

(Gracias a Ben Steward, buen pensamiento ...)

LluviaColonia
fuente
Tal vez envuelva eso en una función principal para que el usuario pueda determinar qué claves se usarían pasándolas, como lo hizo el OP.
Ben Steward
11

Puede usar un javascript de línea con el método de reducción de matriz y la desestructuración de ES6 para convertir una matriz de pares de valores clave en un objeto.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Faisal Hasnain
fuente
3
Desafortunadamente, esto es O (n ^ 2).
jimrandomh
10

Esto probablemente sea más detallado de lo que desea, pero está solicitando una operación un poco compleja, por lo que el código real podría estar involucrado (el horror).

Mi recomendación, con zipObjecteso es bastante lógico:

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

Otra opción, más hacky, usando fromPairs:

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

La función anónima muestra la piratería: no creo que JS garantice el orden de los elementos en la iteración del objeto, por lo que la llamada .values()no funcionará.

djechlin
fuente
No veo nada raro en el uso fromPairsy, de values()hecho , llamar no sirve. Al menos desde el punto de vista de la legibilidad.
x-yuri
6

Otra forma con lodash

crear pares, y luego construir un objeto o ES6 Mapfácilmente

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

o

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

Aquí hay un ejemplo de trabajo

Koushik Chatterjee
fuente
1
Lo bueno de esta solución es que también es factible en ES simple:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante
@fregante, Chrome 73+ solo caniuse.com/?search=fromEntries
d9k
6

También puede resolver sin usar ninguna función lodash como esta:

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

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


console.log(output);

ingrese la descripción de la imagen aquí

Zeeshan Afzal Satti
fuente