lodash: mapowanie tablicy na obiekt

90

Czy istnieje wbudowana funkcja lodash, aby to zrobić:

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

I wypisz to:

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

W tej chwili po prostu używam 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');

Zastanawiam się, czy istnieje skrót lodash.

rdzeń
źródło

Odpowiedzi:

132

Inny sposób z lodash 4.17.2

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

lub

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

lub z _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)
stasovlas
źródło
@Akrikos _.keyByprzekształci całą tablicę w obiekt, podczas gdy pytanie dotyczy głównie posiadania jednego elementu z każdego obiektu w tablicy jako klucza i jednego innego elementu jako jego wartości. Jeśli _.keyByzostanie użyte, wszystkie wartości będą obiektami.
Mustafa Ehsan Alokozay
Dzięki @MustafaEhsanAlokozay Masz rację, ta odpowiedź nie jest właściwa. Usunę mój komentarz, ponieważ nie jest pomocny. To może sprawić, że twój komentarz będzie wyglądał dziwnie, ale lepiej, niż gdyby mój niepoprawny komentarz pozostał dłużej.
Akrikos
53

Powinieneś używać _.keyBy, aby łatwo przekonwertować tablicę na obiekt.

Dokumenty tutaj

Przykładowe użycie poniżej:

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>

W razie potrzeby możesz manipulować tablicą przed użyciem _.keyBy lub obiektem po użyciu _.keyBy, aby uzyskać dokładnie pożądany wynik.

danday74
źródło
2
Spójrz najpierw na to, aby zrozumieć większość odpowiedzi, na które głosował Stasovlas.
Roman Susi,
3
To fajna odpowiedź, ale NIE odpowiada na pytanie. Wartości powinny być łańcuchami, a nie obiektami.
Dem Pilafian
34

Tak, jest tutaj , używając_.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
źródło
Po raz kolejny reduce()pojawia się inny przypadek użycia. Sprytny sposób na zrobienie tego!
Dan
Czy ktoś ma wersję na maszynie?
pan Bjerre
W rzeczywistości jest to matematycznie prawdziwe, że można zaimplementować dosłownie dowolną akcję iteracji za pomocą funkcji redukuj / wstrzykuj, ponieważ redukcja jest izomorficzna z listą. Jednak ta elastyczność ma swoją cenę w czytelności. Nie używaj, _.reducechyba że dokładnie oddaje to, co próbujesz zrobić: w każdym innym przypadku znacznie przesłania sens kodu. Osobiście wolę _.zipObjectrozwiązanie @djechlin - w przeciwnym razie _.keyBy/ _.mapValuespodejście.
Robert Fischer
15

Wygląda na to, że jest to zadanie dla Object. assign:

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

Edytowany do zawijania jako funkcja podobna do OP, wyglądałaby tak:

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

(Dzięki Benowi Stewardowi, dobre myślenie ...)

RainedColony
źródło
Może zawiń to w funkcję nadrzędną, aby użytkownik mógł określić, jakie klucze będą używane, przekazując je, tak jak w przypadku OP.
Ben Steward
11

Możesz użyć javascript z jedną linijką z metodą redukcji tablic i destrukturyzacją ES6, aby przekonwertować tablicę par klucz-wartość na obiekt.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Faisal Hasnain
źródło
3
Niestety to jest O (n ^ 2).
jimrandomh
10

Jest to prawdopodobnie bardziej szczegółowe niż chcesz, ale prosisz o nieco złożoną operację, więc może być zaangażowany rzeczywisty kod (horror).

Moje zalecenie, z zipObjecttym całkiem logiczne:

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

Inna opcja, bardziej hackerska, używając fromPairs:

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

Funkcja anonimowa pokazuje hacking - nie wierzę, że JS gwarantuje kolejność elementów w iteracji obiektu, więc callling .values()nie wystarczy.

djechlin
źródło
Nie widzę nic dziwnego w używaniu fromPairs, a dzwonienie values()rzeczywiście nie wystarczy. Przynajmniej z punktu widzenia czytelności.
x-yuri
6

Inny sposób z lodash

tworząc pary, a następnie konstruuj obiekt lub ES6 Mapłatwo

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

lub

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

Oto działający przykład

Koushik Chatterjee
źródło
1
Object.fromEntries(params.map(v => [v.name, v.input]))
Zaletą
@fregante, Chrome 73+, tylko caniuse.com/?search=fromEntries
d9k
6

Może również rozwiązać problem bez użycia funkcji lodash, takiej jak ta:

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

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


console.log(output);

wprowadź opis obrazu tutaj

Zeeshan Afzal Satti
źródło