Convert object array to hash map, indexed by an attribute value of the Object

JavascriptArraysHashmap

Javascript Problem Overview


Use Case

The use case is to convert an array of objects into a hash map based on string or function provided to evaluate and use as the key in the hash map and value as an object itself. A common case of using this is converting an array of objects into a hash map of objects.

Code

The following is a small snippet in JavaScript to convert an array of objects to a hash map, indexed by the attribute value of object. You can provide a function to evaluate the key of hash map dynamically (run time).

function isFunction(func) {
	return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hashmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
 *		Returns :- Object {123: Object, 345: Object}
 *
 *		[{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
 *		Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key) {
	var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
	this.forEach(function (obj){
		_hashMap[getKey(obj)] = obj;
	});
	return _hashMap;
};

You can find the gist here: Converts Array of Objects to HashMap.

Javascript Solutions


Solution 1 - Javascript

This is fairly trivial to do with Array.prototype.reduce:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce(function(map, obj) {
    map[obj.key] = obj.val;
    return map;
}, {});

console.log(result);
// { foo:'bar', hello:'world' }

Note: Array.prototype.reduce() is IE9+, so if you need to support older browsers you will need to polyfill it.

Solution 2 - Javascript

Using ES6 Map (pretty well supported), you can try this:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = new Map(arr.map(i => [i.key, i.val]));

// When using TypeScript, need to specify type:
// var result = arr.map((i): [string, string] => [i.key, i.val])

// Unfortunately maps don't stringify well.  This is the contents in array form.
console.log("Result is: " + JSON.stringify([...result])); 
// Map {"foo" => "bar", "hello" => "world"}

Solution 3 - Javascript

You can use the new Object.fromEntries() method.

Example:

const array = [

{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'} ]

const hash = Object.fromEntries( array.map(e => [e.key, e.value]) )

console.log(hash) // {a: b, x: y}

Solution 4 - Javascript

Using ES6 spread + Object.assign:

array = [{key: 'a', value: 'b', redundant: 'aaa'}, {key: 'x', value: 'y', redundant: 'zzz'}]

const hash = Object.assign({}, ...array.map(s => ({[s.key]: s.value})));

console.log(hash) // {a: b, x: y}

Solution 5 - Javascript

With lodash, this can be done using keyBy:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = _.keyBy(arr, o => o.key);

console.log(result);
// Object {foo: Object, hello: Object}

Solution 6 - Javascript

Using the spread operator:

const result = arr.reduce(
    (accumulator, target) => ({ ...accumulator, [target.key]: target.val }),
    {});

Demonstration of the code snippet on jsFiddle.

Solution 7 - Javascript

You can use Array.prototype.reduce() and actual JavaScript Map instead just a JavaScript Object.

let keyValueObjArray = [
  { key: 'key1', val: 'val1' },
  { key: 'key2', val: 'val2' },
  { key: 'key3', val: 'val3' }
];

let keyValueMap = keyValueObjArray.reduce((mapAccumulator, obj) => {
  // either one of the following syntax works
  // mapAccumulator[obj.key] = obj.val;
  mapAccumulator.set(obj.key, obj.val);

  return mapAccumulator;
}, new Map());

console.log(keyValueMap);
console.log(keyValueMap.size);

What is different between Map And Object?
Previously, before Map was implemented in JavaScript, Object has been used as a Map because of their similar structure.
Depending on your use case, if u need to need to have ordered keys, need to access the size of the map or have frequent addition and removal from the map, a Map is preferable.

Quote from MDN document:
Objects are similar to Maps in that both let you set keys to values, retrieve those values, delete keys, and detect whether something is stored at a key. Because of this (and because there were no built-in alternatives), Objects have been used as Maps historically; however, there are important differences that make using a Map preferable in certain cases:

  • The keys of an Object are Strings and Symbols, whereas they can be any value for a Map, including functions, objects, and any primitive.

  • The keys in Map are ordered while keys added to object are not. Thus, when iterating over it, a Map object returns keys in order of insertion.

  • You can get the size of a Map easily with the size property, while the number of properties in an Object must be determined manually.

  • A Map is an iterable and can thus be directly iterated, whereas iterating over an Object requires obtaining its keys in some fashion and iterating over them.

  • An Object has a prototype, so there are default keys in the map that could collide with your keys if you're not careful. As of ES5 this can be bypassed by using map = Object.create(null), but this is seldom done.

  • A Map may perform better in scenarios involving frequent addition and removal of key pairs.

Solution 8 - Javascript

es2015 version:

const myMap = new Map(objArray.map(obj => [ obj.key, obj.val ]));

Solution 9 - Javascript

There are better ways to do this as explained by other posters. But if I want to stick to pure JS and ol' fashioned way then here it is:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' },
    { key: 'hello', val: 'universe' }
];

var map = {};
for (var i = 0; i < arr.length; i++) {
    var key = arr[i].key;
    var value = arr[i].val;

    if (key in map) {
        map[key].push(value);
    } else {
        map[key] = [value];
    }
}

console.log(map);

Solution 10 - Javascript

 Tersiest

list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {})

const list = [ { name: 'abc', value: 123 }, { name: 'xyz', value: 789 }, { name: 'she', value: 'her' }, { name: 'he', value: 'him'} ]

console.log(
  list.reduce((obj, item) => ({...obj, [item.name]: item.value}), {})
)

Solution 11 - Javascript

If you want to convert to the new ES6 Map do this:

var kvArray = [['key1', 'value1'], ['key2', 'value2']];
var myMap = new Map(kvArray);

Why should you use this type of Map? Well that is up to you. Take a look at this.

Solution 12 - Javascript

This is what I'm doing in TypeScript I have a little utils library where I put things like this

export const arrayToHash = (array: any[], id: string = 'id') => 
         array.reduce((obj, item) =>  (obj[item[id]] = item , obj), {})

usage:

const hash = arrayToHash([{id:1,data:'data'},{id:2,data:'data'}])

or if you have a identifier other than 'id'

const hash = arrayToHash([{key:1,data:'data'},{key:2,data:'data'}], 'key')

Solution 13 - Javascript

A small improvement on the reduce usage:

var arr = [
    { key: 'foo', val: 'bar' },
    { key: 'hello', val: 'world' }
];

var result = arr.reduce((map, obj) => ({
    ...map,
    [obj.key] = obj.val
}), {});

console.log(result);
// { foo: 'bar', hello: 'world' }

Solution 14 - Javascript

With lodash:

const items = [
    { key: 'foo', value: 'bar' },
    { key: 'hello', value: 'world' }
];

const map = _.fromPairs(items.map(item => [item.key, item.val]));

// OR: if you want to index the whole item by key:
// const map = _.fromPairs(items.map(item => [item.key, item]));

The lodash fromPairs function reminds me about zip function in Python

Link to lodash

Solution 15 - Javascript

the reduce version seems not work. i go with following.

   let map = {};
    items.forEach(v=>{
      map [v.xxx] = v;
    });

Solution 16 - Javascript

Using simple Javascript

var createMapFromList = function(objectList, property) {
    var objMap = {};
    objectList.forEach(function(obj) {
      objMap[obj[property]] = obj;
    });
    return objMap;
  };
// objectList - the array  ;  property - property as the key

Solution 17 - Javascript

try

let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});

let arr=[
  {id:123, name:'naveen'}, 
  {id:345, name:"kumar"}
];

let fkey = o => o.id; // function changing object to string (key)

let toHashMap = (a,f) => a.reduce((a,c)=> (a[f(c)]=c,a),{});

console.log( toHashMap(arr,fkey) );

// Adding to prototype is NOT recommented:
//
// Array.prototype.toHashMap = function(f) { return toHashMap(this,f) };
// console.log( arr.toHashMap(fkey) );

Solution 18 - Javascript

I would make it more clear in TypeScript in case someone is interested.

interface Person {
  id: number;
  name: string;
}
type Result = Map<number, string>

const input: Array<Person> = [
  {
    id: 123,
    name: "naveen"
  },
  {
    id: 345,
    name: "kumar"
  },
];
const convertedToMap: Result = input.reduce(
  (map: Result, person: Person) => {
    map.set(person.id, person.name);
    return map;
  },
  new Map()
);

Solution 19 - Javascript

For me, I prefer not to use any map or reduce and just stick with simple for loop.

const array = [
   {key: 'a', value: 'b', redundant: 'aaa'},
   {key: 'x', value: 'y', redundant: 'zzz'}
]

const hash = {};

for (const item of array) {
    hash[item.key] = item;
}

console.log(hash);

Solution 20 - Javascript

Following is small snippet i've created in javascript to convert array of objects to hash map, indexed by attribute value of object. You can provide a function to evaluate the key of hash map dynamically (run time).

function isFunction(func){
    return Object.prototype.toString.call(func) === '[object Function]';
}

/**
 * This function converts an array to hash map
 * @param {String | function} key describes the key to be evaluated in each object to use as key for hasmap
 * @returns Object
 * @Example 
 *      [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap("id")
        Returns :- Object {123: Object, 345: Object}
        
        [{id:123, name:'naveen'}, {id:345, name:"kumar"}].toHashMap(function(obj){return obj.id+1})
        Returns :- Object {124: Object, 346: Object}
 */
Array.prototype.toHashMap = function(key){
    var _hashMap = {}, getKey = isFunction(key)?key: function(_obj){return _obj[key];};
    this.forEach(function (obj){
        _hashMap[getKey(obj)] = obj;
    });
    return _hashMap;
};

You can find the gist here : https://gist.github.com/naveen-ithappu/c7cd5026f6002131c1fa

Solution 21 - Javascript

Map the array like this:

const items = [
{ key: 'foo', value: 'bar' },
{ key: 'hello', value: 'world' }
];

let [k,v] = items.map(item => [item.key, item.value])   
console.log([k,v]) 

//Output: [ [ 'foo', 'bar' ], [ 'hello', 'world' ] ]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNaveen IView Question on Stackoverflow
Solution 1 - Javascriptjmar777View Answer on Stackoverflow
Solution 2 - JavascriptmateuscbView Answer on Stackoverflow
Solution 3 - JavascriptFabiano TaioliView Answer on Stackoverflow
Solution 4 - JavascriptshukView Answer on Stackoverflow
Solution 5 - JavascriptsplintorView Answer on Stackoverflow
Solution 6 - JavascriptPedro LopesView Answer on Stackoverflow
Solution 7 - JavascriptJun711View Answer on Stackoverflow
Solution 8 - JavascriptbaryoView Answer on Stackoverflow
Solution 9 - JavascriptBrownRecluseView Answer on Stackoverflow
Solution 10 - JavascriptKing FridayView Answer on Stackoverflow
Solution 11 - JavascriptTiago BértoloView Answer on Stackoverflow
Solution 12 - JavascriptPeterView Answer on Stackoverflow
Solution 13 - JavascriptMor ShemeshView Answer on Stackoverflow
Solution 14 - JavascriptThoView Answer on Stackoverflow
Solution 15 - JavascriptRyanShaoView Answer on Stackoverflow
Solution 16 - JavascriptPartha RoyView Answer on Stackoverflow
Solution 17 - JavascriptKamil KiełczewskiView Answer on Stackoverflow
Solution 18 - JavascriptNguyễn Anh TuấnView Answer on Stackoverflow
Solution 19 - JavascriptYadaView Answer on Stackoverflow
Solution 20 - JavascriptNaveen IView Answer on Stackoverflow
Solution 21 - JavascriptJacmanView Answer on Stackoverflow