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 wi
Not a best one as per performance efficiency, but If you want to skip recursion part from your side and want to keep the code clean and simple then you can stringify it to json and use JSON.parse
with additional parameter (callback) and there you can transform the keys with lodash.
JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v)
Here is an working example:
let obj = { a: 2, b: { c: 2, d: { a: 3 } } };
let mappedObj = JSON.parse(JSON.stringify(obj), (k, v) => _.isObject(v) ? _.mapKeys(v, (_v, _k) => _k + '_hi') : v)
console.log(mappedObj)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>
EDIT: This will map the objects values, not its keys. I misunderstood the question.
function deepMap (obj, cb) {
var out = {};
Object.keys(obj).forEach(function (k) {
var val;
if (obj[k] !== null && typeof obj[k] === 'object') {
val = deepMap(obj[k], cb);
} else {
val = cb(obj[k], k);
}
out[k] = val;
});
return out;
}
And use it as
var lol = deepMap(test, function (v, k) {
return v + '_hi';
});
It will recursively iterate over an objects own enumerable properties and call a CB passing it the current value and key. The values returned will replace the existing value for the new object. It doesn't mutate the original object.
See fiddle: https://jsfiddle.net/1veppve1/
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);
}
},
});
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';
});
I've add a small improvement from Chris Jones's answer.
Following code fix some unintended results of Array elements.
_.mixin({
deeply: function (map) {
var deeplyArray = function (obj, fn) {
return obj.map(function(x) {
return _.isPlainObject(x) ? _.deeply(map)(x, fn) : x;
})
}
return function (obj, fn) {
if (_.isArray(obj)) {
return deeplyArray(obj, fn);
}
return map(_.mapValues(obj, function (v) {
return _.isPlainObject(v) ? _.deeply(map)(v, fn) : _.isArray(v) ?
deeplyArray(v, fn) : v;
}), fn);
}
},
});