# Convert object array to hash map using lodash

The use case is to convert an array of objects into a hash map where one property is the key and the other property is the value. Common case of using this is converting a "link" object in a hypermedia response into a hash map of links.

jsfiddle

function toHashMap(data, name, value) {
return _.zipObject(_.pluck(data, name),
_.pluck(data, value));
}

function toMap(data, name, value) {
return _.reduce(data, function(acc, item) {
acc[item[name]] = item[value];
return acc;
}, {});
}

var data = [
];

console.log(toHashMap(data, 'rel', 'href'));

console.log(toMap(data, 'rel', 'href'));


toHashMap appears much more readable, but less efficient. toMap seems to have the best efficiency at the expense of readability.

Is there a more elegant solution - i.e. both readable and efficient? I suspect that Lodash might have a function to do this already, but I haven't found anything like this after looking at the API documentation.

I think you are looking for _.keyBy (or _.indexBy in older versions)

_.keyBy(data, 'rel');

• I don't understand why is this the accepted answer since it doesn't give the same result as the exposed functions – Pau Fracés Feb 17 '15 at 15:53
• @PauFracés See below for revised solution. – Pete Mar 13 '15 at 21:14
• Note: Now known as _.keyBy(lodash.com/docs#keyBy). – 2540625 Feb 18 '16 at 2:07

# Revised Solution

As per Pau Fracés comment above, here is the complete solution. The solution given by John Anderson would index all objects by the key. However, this would not create a key-value pair map.

To complete the solution of generating a full hash map, the values must be mapped to the key. Using the mapValues function, the values can be extracted from the objects and mapped back to the key or in this case rel.

## Pseudo Code

1. Index all objects by the chosen key.
2. Map all values to the key.

## Code

Below is the complete code with logging enabled. For a non-logging version, remove all lines with the tap function.

var data = [{ rel: 'link1', href: 'url1' },
{ rel: 'link2', href: 'url2' },
{ rel: 'link3', href: 'url3' },
{ rel: 'link4', href: 'url4' }];

function log(value) {
document.getElementById("output").innerHTML += JSON.stringify(value, null, 2) + "\n"
}

var hashmap = _.chain(data)
.keyBy('rel')

.tap(log) // Line used just for logging

.mapValues('href')

.tap(log)

.value();
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
<pre id="output"></pre>

• Nice solution! Personally I would go for mapValues instead of transform. With transform you're updating state outside the closure (it is a side-effecting function), whereas with mapValues you are not. – Martijn Jul 7 '15 at 9:14
• @Martijn Oh great suggestion! Makes for a much cleaner solution IMHO. I've updated the solution with your suggestion. Thanks! – Pete Jul 10 '15 at 20:21
• @Pete Awesome! Just realized that lodash v4 renamed indexBy to keyBy – Pau Fracés Feb 11 '16 at 20:22
• Updated to use keyBy – Pete Mar 8 '16 at 13:18
• with lodash-fp this can also be done as a one-liner flow(fpKeyBy('rel'), fpMapValues('href'))(data) (fp-prefixed functions are fp-lodash versions) – Spain Train May 7 '16 at 0:05

In ES7 it's now as simple as:

data.reduce((acc, { rel, href }) => ({ ...acc, [rel]: href }), {});


(without even using Lodash).

• would be great if it worked. but it doesn't seem to work! (node 5.0.0) – Rene Wooller Sep 8 '16 at 0:55
• This is ES7, not ES2015 – Rene Wooller Sep 8 '16 at 1:01
• @ReneWooller Right, sorry. Hard to keep track of what's what when using Babel :) – hon2a Sep 8 '16 at 9:15
• That works, and it's nice to not have to have to have the lodash dependency, but damn if the lodash way isn't a million times more readable. – Thor84no Jan 29 '18 at 10:31
• @digitai My point was mostly that you can easily just inline it in plain JS now. Obviously you could create an abstraction for it, but then you'd likely want to make it more efficient as well (e.g. avoid creating a new object on every pass). If key and value prop names would be external variables, you'd destructure as { [keyProp]: key, [valueProp]: value }. – hon2a Apr 1 at 8:36

A simpler way would be to use "reduce".

var data = [
];

var hashmap = _.reduce(data, function(hash, value) {
var key = value['rel'];
hash[key] = value['href'];
return hash;
}, {});


JSFiddle: https://jsfiddle.net/6txzzxq2/

With reduce you can iterate over the source array with an "accumulator" (in this case, a new object). Above we key the hash by the rel attribute with href as the value.

• You could also use .transform to reduce the amount of code... but that's a matter of personal preference. – Pete Mar 14 '16 at 15:22
• As stated by Martijn in a previous comment, both .reduce and .transform update state outside the closure whereas mapValues does not. So keep this in mind when using .reduce. – Pete Mar 16 '16 at 21:37
• @Pete Updating outside state is not an inherent property of .reduce, but rather of the reducer itself. You can just as well use .reduce without side-effects (see my short answer). – hon2a Mar 24 '16 at 10:42
• @hon2a True... I one thing that bugs me about this particular reduce solution, though, is that 'rel' and 'href' are hardcoded into the callback. It makes it less reusable. I tried to avoid that in the original solution. The maintenance cost of a one-liner to a five-liner is much more appealing to me. As for readability, reduce is less fluent compared keyBy and mapValues to a non-programmer. Granted, all this is at the cost of performance and so it's not the end all of solutions. Thanks for updating to ES2015. – Pete Mar 24 '16 at 13:40
• @Pete I'd argue that a simple use of reduce is actually better readable than keyBy + mapValues(propNameShortcut), as reduce is a native (thus ubiquitous) method that doesn't require you to know the details of a specific (Lodash) API. – hon2a Apr 11 '16 at 10:39

Since lodash 4, you can use _.fromPairs:

var data = [
];

var hashmap = _.fromPairs(data.map(function(item) {
return [item.rel, item.href];
}));

• Is there a way to parameterize 'rel' and 'href' outside of the map method to make the solution more generic? – Pete May 25 '16 at 14:21
• function makePair(keyProperty, valueProperty) { return function(item) { return [item[keyProperty], item[valueProperty]]; }; } var hashmap = _.fromPairs(data.map(makePair('rel', 'href'))); – Ricardo Stuven Aug 28 '17 at 13:20

With Lodash 4:

Using keyBy and mapValues

_.mapValues(_.keyBy(data, 'rel'), v => v.href);


Or:

_.chain(data).keyBy('rel').mapValues(v => v.href).value();


I see a lot of good answers already. I would just like to add one more answer to the list using Ramda's indexBy.

const data = [{
id: 1,
foo: 'bar'
},
{
id: 2,
baz: 'lorem'
}
];

const dataById = R.indexBy(R.prop('id'), data);
console.log(dataById)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

I hope it helps someone else :)

• This isn't really a review of the code provided, is it? – Mast Jan 15 '18 at 20:20
• Sorry misunderstood the use of this website. More familiar with StackOverflow :) – Abhishek Ghosh Jan 16 '18 at 0:33