For my current project, I'm working with an API that returns data formatted like this:
{
groups: [
{
items: [
{
points: [
{ name: "name1", ... },
{ name: "name2", ... },
{ name: "name3", ... },
...
],
...
},
...
]
},
...
],
...
};
I'd like to create a pure function, mapValues
, that takes in an object in the above format, as well as an object mapping each name
to a value
, and returns the same structure, but with each point
containing the value
that corresponds to its name
.
For example, calling mapValues(data, { name1: "value1", name2: "value2", name3: "value3" })
should return this:
{
groups: [
{
items: [
{
points: [
{ name: "name1", value: "value1", ... },
{ name: "name2", value: "value2", ... },
{ name: "name3", value: "value3", ... },
...
],
...
},
...
]
},
...
],
...
};
Here's my first pass:
function mapValues(data, values) {
return _.extend({}, data, {
groups: _.map(ui.groups, (group) => {
return _.extend({}, group, {
items: _.map(group.items, (item) => {
return _.extend({}, item, {
points: _.map(item.points, (point) => {
return _.extend({ value: values[point.name] }, point);
})
});
})
});
})
});
}
That works, but there's quite a bit of nesting a duplicate code. For my second attempt, I reached for recursion.
function mapValues(data, values) {
return (function recursiveMap(object, attributes) {
if (attributes.length === 0) { return _.extend({ value: values[object.name] }, object); }
let key = attributes[0];
return _.extend({}, object, {
[key]: _.map(object[key], child => recursiveMap(child, attributes.slice(1)))
});
})(ui, ["groups", "items", "points"]);
}
That works too, but it's difficult to read and not very concise.
Is there a cleaner way to recursively map an object using Lodash? Ideally, I'm looking for a functional approach.