122

Is there a built-in lodash function to take this:

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

And output this:

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

Right now I'm just using 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');

Wondering if there's a lodash short-cut.

core
  • 31,265
  • 43
  • 134
  • 192

8 Answers8

171

Another way with lodash 4.17.2

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

or

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

or with _.reduce

_.reduce(
    params,
    (acc, { name, input }) => ({ ...acc, [name]: input }),
    {}
)
Mustafa Ehsan Alokozay
  • 5,133
  • 2
  • 23
  • 30
stasovlas
  • 6,706
  • 2
  • 27
  • 28
  • @Akrikos the `_.keyBy` will transform the entire array to an object, whereas the question is mostly about having one item from each object in array as key and one other item as its value. If `_.keyBy` is used, then all values will be objects. – Mustafa Ehsan Alokozay Oct 19 '19 at 09:40
  • Thanks @MustafaEhsanAlokozay You're right, that answer does not do the exact right thing. I'll delete my comment as it's not helpful. That may make your comment look weird, but better that than have my incorrect comment stay up any longer. – Akrikos Mar 06 '20 at 19:19
73

You should be using _.keyBy to easily convert an array to an object.

Docs here

Example usage below:

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>

If required, you can manipulate the array before using _.keyBy or the object after using _.keyBy to get the exact desired result.

danday74
  • 45,909
  • 39
  • 198
  • 245
40

Yep it is here, using _.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
  • 6,997
  • 8
  • 31
  • 49
  • 1
    Yet again `reduce()` swoops in with another use case. Smart way of doing it! – Dan Jul 18 '19 at 15:53
  • Anyone got the typescripted version of this? – mr.bjerre Feb 05 '20 at 18:49
  • The reality is that's mathematically true that you can implement literally any iteration action using reduce/inject, since reduce is isomorphic to a list. However, that flexibility comes with a price in readability. Don't use `_.reduce` unless that accurately expresses what you're trying to do: it significantly obscures the point of the code in any other case. I personally prefer the `_.zipObject` solution by @djechlin -- failing that, the `_.keyBy`/`_.mapValues` approach. – Robert Fischer Aug 20 '20 at 14:01
23

This seems like a job for Object.assign:

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

Edited to wrap as a function similar to OP's, this would be:

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

(Thanks to Ben Steward, good thinking...)

RainedColony
  • 231
  • 2
  • 4
12

This is probably more verbose than you want, but you're asking for a slightly complex operation so actual code might be involved (the horror).

My recommendation, with zipObject that's pretty logical:

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

Another option, more hacky, using fromPairs:

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

The anonymous function shows the hackiness -- I don't believe JS guarantees order of elements in object iteration, so callling .values() won't do.

djechlin
  • 57,408
  • 33
  • 153
  • 271
  • I don't see anything hacky about using `fromPairs`, and calling `values()` indeed won't do. At least from readability standpoint. – x-yuri Aug 20 '17 at 12:03
12

You can use one liner javascript with array reduce method and ES6 destructuring to convert array of key value pairs to object.

arr.reduce((map, { name, input }) => ({ ...map, [name]: input }), {});
Faisal Hasnain
  • 415
  • 5
  • 8
8

Another way with lodash

creating pairs, and then either construct a object or ES6 Map easily

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

or

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

Here is a working example

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

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

console.log(obj);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
Koushik Chatterjee
  • 3,938
  • 3
  • 16
  • 31
  • 1
    The good part of this solution is that it's also feasible in plain ES: `Object.fromEntries(params.map(v => [v.name, v.input]))` – fregante Jun 03 '20 at 12:55
  • 1
    @fregante, Chrome 73+ only https://caniuse.com/?search=fromEntries – d9k Oct 23 '20 at 09:49
6

It can also solve without using any lodash function like this:

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

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


console.log(output);

enter image description here