[javascript] Map over object preserving keys

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}

This question is related to javascript underscore.js lodash

The answer is


_.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}

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).


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

_x000D_
_x000D_
var mapped = _.reduce({ one: 1, two: 2, three: 3 }, function(obj, val, key) {_x000D_
    obj[key] = val*3;_x000D_
    return obj;_x000D_
}, {});_x000D_
_x000D_
console.log(mapped);
_x000D_
<script src="http://underscorejs.org/underscore-min.js"></script>_x000D_
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
_x000D_
_x000D_
_x000D_


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
  }, {})
}

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 ) 

_.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.


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


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;
};

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);
}

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})));

Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to underscore.js

Add property to an array of objects Comparing two arrays of objects, and exclude the elements who match values into new array in JS using lodash .groupBy. how to add your own keys for grouped output? Remove Duplicate objects from JSON Array Lodash .clone and .cloneDeep behaviors find the array index of an object with a specific key value in underscore Bootstrap - Uncaught TypeError: Cannot read property 'fn' of undefined Map over object preserving keys Remove an item from array using UnderscoreJS Find by key deep in a nested array

Examples related to lodash

Can't perform a React state update on an unmounted component Angular 4 HttpClient Query Parameters use Lodash to sort array of object by value How to group an array of objects by key Removing object properties with Lodash How to merge two arrays of objects by ID using lodash? Error: EACCES: permission denied Replacing objects in array lodash: mapping array to object Correct way to import lodash