Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deeply map object keys with JavaScript (lodash)?

Tags:

https://lodash.com/docs#mapKeys

Is it possible to map an Object's keys deeply using Lodash? If not, is there another library providing this functionality (if grouped with other deep iteration and manipulation functionality, even better!)? Else, how would one go about implementing this? The main struggle I see is in identifying pure key/value objects that are safely, deeply iterable. It's easy to throw out Arrays, but it's important to note that the function shouldn't try to deeply iterate on other objects like a regex, for example.

Intended result-

var obj = { a: 2, b: { c: 2, d: { a: 3 } } }; _.deepMapKeys(obj, function (val, key) {   return key + '_hi'; }); // => { a_hi: 2, b_hi: { c_hi: 2, d_hi: { a_hi: 3 } } } 
like image 485
Tejas Manohar Avatar asked Jan 28 '16 07:01

Tejas Manohar


People also ask

Can javascript Map have object as key?

A key of an object must be a string or a symbol, you cannot use an object as a key. An object does not have a property that represents the size of the map.

Is Deep equal Lodash?

The Lodash _. isEqual() Method performs a deep comparison between two values to determine if they are equivalent. This method supports comparing arrays, array buffers, boolean, date objects, maps, numbers, objects, regex, sets, strings, symbols, and typed arrays.

Does Lodash work with maps?

Lodash helps in working with arrays, collection, strings, objects, numbers etc. The _. map() method creates an array of values by running each element in collection through the iteratee. There are many lodash methods that are guarded to work as iteratees for methods like _.

How do you compare objects in Lodash?

In Lodash, we can deeply compare two objects using the _. isEqual() method. This method will compare both values to determine if they are equivalent.


2 Answers

Here's how you can do that in lodash:

_.mixin({     'deepMapKeys': function (obj, fn) {          var x = {};          _.forOwn(obj, function(v, k) {             if(_.isPlainObject(v))                 v = _.deepMapKeys(v, fn);             x[fn(v, k)] = v;         });          return x;     } }); 

and here's a more abstract mixin, that recursively applies any given mapper:

_.mixin({     deep: function (obj, mapper) {         return mapper(_.mapValues(obj, function (v) {             return _.isPlainObject(v) ? _.deep(v, mapper) : v;         }));     }, }); 

Usage (returns the same as above):

obj = _.deep(obj, function(x) {     return _.mapKeys(x, function (val, key) {         return key + '_hi';     }); }); 

Another option, with more elegant syntax:

_.mixin({     deeply: function (map) {         return function(obj, fn) {             return map(_.mapValues(obj, function (v) {                 return _.isPlainObject(v) ? _.deeply(map)(v, fn) : v;             }), fn);         }     }, });   obj = _.deeply(_.mapKeys)(obj, function (val, key) {     return key + '_hi'; }); 
like image 103
georg Avatar answered Sep 17 '22 14:09

georg


In extention of georg's answer, here's what I'm using. This extended mixin adds the ability to map arrays of objects within the object too, a simple but important change.

_.mixin({     deeply: function (map) {       return function (obj, fn) {         return map(_.mapValues(obj, function (v) {           return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ? v.map(function(x) {             return _.deeply(map)(x, fn);           }) : v;         }), fn);       }     },   }); 
like image 25
GTWelsh Avatar answered Sep 19 '22 14:09

GTWelsh