Lodash: mapeando a matriz para o objeto

93

Existe uma função Lodash integrada para fazer isso:

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

E produza isto:

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

No momento, estou apenas 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');

Querendo saber se há um atalho lodash.

testemunho
fonte

Respostas:

138

Outra maneira com lodash 4.17.2

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

ou

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

ou com _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)
Stasovlas
fonte
@Akrikos _.keyByirá transformar todo o array em um objeto, enquanto a questão é principalmente sobre ter um item de cada objeto no array como chave e um outro item como seu valor. Se _.keyByfor usado, todos os valores serão objetos.
Mustafa Ehsan Alokozay
Obrigado @MustafaEhsanAlokozay Você está certo, essa resposta não faz exatamente a coisa certa. Vou deletar meu comentário porque não ajuda. Isso pode fazer o seu comentário parecer estranho, mas é melhor do que manter o meu comentário incorreto por mais tempo.
Akrikos
55

Você deve usar _.keyBy para converter facilmente uma matriz em um objeto.

Docs aqui

Exemplo de uso abaixo:

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 necessário, você pode manipular a matriz antes de usar _.keyBy ou o objeto depois de usar _.keyBy para obter o resultado desejado exato.

danday74
fonte
2
Olhe primeiro para isso para entender a resposta mais votada por stasovlas.
Roman Susi
5
Esta é uma resposta legal, mas NÃO responde à pergunta. Os valores devem ser strings, não objetos.
Dem Pilafian
34

Sim, está aqui , usando_.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
fonte
Mais uma vez, reduce()surge com outro caso de uso. Maneira inteligente de fazer isso!
Dan
Alguém tem a versão datilografada disso?
sr.bjerre
A realidade é que é matematicamente verdadeiro que você pode implementar literalmente qualquer ação de iteração usando reduzir / injetar, uma vez que reduzir é isomórfico a uma lista. No entanto, essa flexibilidade tem um preço em legibilidade. Não use, a _.reducemenos que expresse com precisão o que você está tentando fazer: em qualquer outro caso, obscurece significativamente o ponto do código. Eu pessoalmente prefiro a _.zipObjectsolução por @djechlin - caso contrário, a abordagem _.keyBy/ _.mapValues.
Robert Fischer de
16

Isso parece um trabalho para Object.assign:

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

Editado para empacotar como uma função semelhante aos OPs, seria:

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

(Obrigado a Ben Steward, boa ideia ...)

RainedColony
fonte
Talvez envolva isso em uma função pai para que o usuário possa determinar quais chaves seriam usadas passando-as, como o OP fez.
Ben Steward
11

Você pode usar um javascript de liner com método de redução de matriz e desestruturação ES6 para converter a matriz de pares de valores-chave em objeto.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Faisal Hasnain
fonte
3
Infelizmente, este é O (n ^ 2).
Jimrandomh
10

Provavelmente, isso é mais detalhado do que você deseja, mas está solicitando uma operação um pouco complexa, portanto, o código real pode estar envolvido (o horror).

Minha recomendação, com zipObjectisso é muito lógico:

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

Outra opção, mais hacky, usando fromPairs:

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

A função anônima mostra a hackeabilidade - não acredito que JS garanta a ordem dos elementos na iteração do objeto, então callling .values()não servirá.

Djechlin
fonte
Não vejo nada estranho sobre o uso fromPairs, e chamar de values()fato não funciona. Pelo menos do ponto de vista da legibilidade.
x-yuri de
6

Outra maneira com lodash

criar pares e, em seguida, construir um objeto ou ES6 Mapfacilmente

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

ou

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

Aqui está um exemplo prático

Koushik Chatterjee
fonte
1
A parte boa dessa solução é que também é viável no ES simples:Object.fromEntries(params.map(v => [v.name, v.input]))
fregante
@fregante, Chrome 73+ apenas caniuse.com/?search=fromEntries
d9k
6

Ele também pode resolver sem usar qualquer função 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);

insira a descrição da imagem aqui

Zeeshan Afzal Satti
fonte