Given an array of objects like this:
var data = [
{key: 'a', val: '1'},
{key: 'a', val: '2'},
{key: 'b', val: '3'},
{key: 'c', val: '4'},
{key: 'c', val: '5'},
{key: 'c', val: '6'}
];
I would like to convert it to this:
var desiredResults = {
'a': [1, 2],
'b': [3],
'c': [4, 5, 6]
};
I've found two ways to achieve this so far with lodash-fp
, but I'm still wondering if there's a better way.
The first way is somewhat procedural:
var out = _(data)
.transform(function(out, item) {
out[item.key] = out[item.key] || [];
out[item.key].push(item.val);
}, {});
The second way is in the point-free style I was hoping to achieve:
var out = _(data)
.groupBy(_.property('key'))
.mapValues(_.map(_.property('val')))
.value();
// Yes, I know that _.property is implied if I just pass a string
However, this is more cluttered than I'd like: I have to iterate over the intermediate results to transform the grouped values, and I think it obscures what the code is trying to accomplish. I can't transform first, though, as the transformation I want removes the keys!
Is there anything like a groupByTransforming(groupIteratee, transformIteratee)
method?
I don't know anything about LoDash (sorry), but I have a simple function that will do what you want that just uses vanilla JS:
/**
* Maps an array of objects into a single object,
* grouped by one property and supplying another.
* @param {Array} input The array of objects containg data
* @param {String} groupBy The name of the property to group the elements by
* @param {String} groupProp The property to push into each array
* @return {Object} The mapped object.
*/
function mapToObject(input, groupBy, groupProp) {
var obj = {};
// Loop through the data
input.forEach(function (data) {
// If the output object doesn't contain the key,
// make it as an empty array
if (!obj[data[groupBy]]) {
obj[data[groupBy]] = [];
};
// Push the value into the obj[groupBy] array
obj[data[groupBy]].push(data[groupProp]);
});
return obj;
}
In your case you would use it like this:
mapToObject(data, 'key', 'val'), so it'd return an Object of the data grouped by 'key' and with the values of 'val'. See the snippet below for an example:
var data = [
{key: 'a', val: '1'},
{key: 'a', val: '2'},
{key: 'b', val: '3'},
{key: 'c', val: '4'},
{key: 'c', val: '5'},
{key: 'c', val: '6'}
];
/**
* Maps an array of objects into a single object,
* grouped by one property and supplying another.
* @param {Array} input The array of objects containg data
* @param {String} groupBy The name of the property to group the elements by
* @param {String} groupProp The property to push into each array
* @return {Object} The mapped object.
*/
function mapToObject(input, groupBy, groupProp) {
var obj = {};
// Loop through the data
input.forEach(function (data) {
// If the output object doesn't contain the key,
// make it as an empty array
if (!obj[data[groupBy]]) {
obj[data[groupBy]] = [];
};
// Push the value into the obj[groupBy] array
obj[data[groupBy]].push(data[groupProp]);
});
return obj;
}
// Just to show example output:
document.write(JSON.stringify(mapToObject(data, 'key', 'val')));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With