Map over object preserving keys

Javascriptunderscore.jsLodash

Javascript Problem Overview


The map function in underscore.js, if called with a javascript object, returns an array of values mapped from the object's values.

_.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; });
=> [3, 6, 9]

is there a way to make it preserve the keys? ie, I want a function that returns

{one: 3, two: 6, three: 9}

Javascript Solutions


Solution 1 - Javascript

With Underscore

Underscore provides a function _.mapObject to map the values and preserve the keys.

_.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });

// => { one: 3, two: 6, three: 9 }

DEMO


With Lodash

Lodash provides a function _.mapValues to map the values and preserve the keys.

_.mapValues({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; });

// => { one: 3, two: 6, three: 9 }

DEMO

Solution 2 - Javascript

I managed to find the required function in lodash, a utility library similar to underscore.

http://lodash.com/docs#mapValues

> _.mapValues(object, [callback=identity], [thisArg]) >
> > Creates an object with the same keys as object and values generated by > running each own enumerable property of object through the callback. > The callback is bound to thisArg and invoked with three arguments; > (value, key, object).

Solution 3 - Javascript

var mapped = _.reduce({ one: 1, two: 2, three: 3 }, function(obj, val, key) {
    obj[key] = val*3;
    return obj;
}, {});

console.log(mapped);

<script src="http://underscorejs.org/underscore-min.js"></script>
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>

Solution 4 - Javascript

How about this version in plain JS (ES6 / ES2015)?

let newObj = Object.assign(...Object.keys(obj).map(k => ({[k]: obj[k] * 3})));

jsbin

If you want to map over an object recursively (map nested obj), it can be done like this:

const mapObjRecursive = (obj) => {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === 'object') obj[key] = mapObjRecursive(obj[key]);
    else obj[key] = obj[key] * 3;
  });
  return obj;
};

jsbin

Since ES7 / ES2016 you can use Object.entries instead of Object.keys like this:

let newObj = Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * 3})));

And since ES2019 you can use Object.fromEntries.

let newObj = Object.fromEntries(Object.entries(obj).map(([k, v]) => ([k, v * 3])))

Solution 5 - Javascript

I know this is old, but now Underscore has a new map for objects :

_.mapObject(object, iteratee, [context]) 

You can of course build a flexible map for both arrays and objects

_.fmap = function(arrayOrObject, fn, context){
    if(this.isArray(arrayOrObject))
      return _.map(arrayOrObject, fn, context);
    else
      return _.mapObject(arrayOrObject, fn, context);
}

Solution 6 - Javascript

I know it's been a long time, but still the most obvious solution via fold (aka reduce in js) is missing, for the sake of completeness i'll leave it here:

function mapO(f, o) {
  return Object.keys(o).reduce((acc, key) => {
    acc[key] = f(o[key])
    return acc
  }, {})
}

Solution 7 - Javascript

_.map returns an Array, not an Object.

If you want an object you're better off using a different function, like each; if you really want to use map you could do something like this:

Object.keys(object).map(function(value, index) {
   object[value] *= 3;
})

but that is confusing, when seeing map one would expect to have an array as result and then make something with it.

Solution 8 - Javascript

I think you want a mapValues function (to map a function over the values of an object), which is easy enough to implement yourself:

mapValues = function(obj, f) {
  var k, result, v;
  result = {};
  for (k in obj) {
    v = obj[k];
    result[k] = f(v);
  }
  return result;
};

Solution 9 - Javascript

const mapObject = (obj = {}, mapper) =>
  Object.entries(obj).reduce(
    (acc, [key, val]) => ({ ...acc, [key]: mapper(val) }),
    {},
  );

Solution 10 - Javascript

A mix fix for the underscore map bug :P

_.mixin({ 
	mapobj : function( obj, iteratee, context ) {
		if (obj == null) return [];
	    iteratee = _.iteratee(iteratee, context);
	    var keys = obj.length !== +obj.length && _.keys(obj),
	        length = (keys || obj).length,
	        results = {},
	        currentKey;
	    for (var index = 0; index < length; index++) {
	      currentKey = keys ? keys[index] : index;
	      results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
	    }
	    if ( _.isObject( obj ) ) {
	    	return _.object( results ) ;
	    } 
	    return results;
	}
}); 

A simple workaround that keeps the right key and return as object It is still used the same way as i guest you could used this function to override the bugy _.map function

or simply as me used it as a mixin

_.mapobj ( options , function( val, key, list ) 

Solution 11 - Javascript

You can use _.mapValues(users, function(o) { return o.age; }); in Lodash and _.mapObject({ one: 1, two: 2, three: 3 }, function (v) { return v * 3; }); in Underscore.

Check out the cross-documentation here: http://jonathanpchen.com/underdash-api/#mapvalues-object-iteratee-identity

Solution 12 - Javascript

_.map using lodash like loop to achieve this

 var result={};
_.map({one: 1, two: 2, three: 3}, function(num, key){ result[key]=num * 3; });
console.log(result)

//output
{one: 1, two: 2, three: 3}

Reduce is clever looks like above answare

_.reduce({one: 1, two: 2, three: 3}, function(result, num, key) {
  result[key]=num * 3
  return result;
}, {});

//output
{one: 1, two: 2, three: 3}

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
QuestionxuanjiView Question on Stackoverflow
Solution 1 - JavascriptGG.View Answer on Stackoverflow
Solution 2 - JavascriptxuanjiView Answer on Stackoverflow
Solution 3 - JavascriptkunalgolaniView Answer on Stackoverflow
Solution 4 - JavascriptRotaretiView Answer on Stackoverflow
Solution 5 - JavascriptRayjaxView Answer on Stackoverflow
Solution 6 - JavascriptDarwinView Answer on Stackoverflow
Solution 7 - JavascriptAlberto ZaccagniView Answer on Stackoverflow
Solution 8 - JavascriptjoyrexusView Answer on Stackoverflow
Solution 9 - JavascriptNigel KirbyView Answer on Stackoverflow
Solution 10 - JavascriptPascalView Answer on Stackoverflow
Solution 11 - JavascriptluxonView Answer on Stackoverflow
Solution 12 - JavascriptßãlãjîView Answer on Stackoverflow