Steps to create the groupBy function, create an object as initial value for our result object. inside the array reduce, create an array for each distinct key value and push the currentValue if the key value present in the currentValue.
The most efficient method to group by a key on an array of objects in js is to use the reduce function. The reduce() method executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
Use reduce() to Group an Array of Objects in JavaScript The most efficient way to group an array of objects in JavaScript is to use the reduce() function. This method executes each array element's (specified) reducer function and produces a single output value.
{} is shorthand for creating an empty object. You can consider this as the base for other object types. Object provides the last link in the prototype chain that can be used by all other objects, such as an Array . [] is shorthand for creating an empty array.
Assuming the original list is contained in a variable named list
:
_
.chain(list)
.groupBy('type')
.map(function(value, key) {
return {
type: key,
foods: _.pluck(value, 'food')
}
})
.value();
Without using underscore:
var origArr = [
{food: 'apple', type: 'fruit'},
{food: 'potato', type: 'vegetable'},
{food: 'banana', type: 'fruit'}
];
/*[
{type: 'fruit', foods: ['apple', 'banana']},
{type: 'vegetable', foods: ['potato']}
]*/
function transformArr(orig) {
var newArr = [],
types = {},
i, j, cur;
for (i = 0, j = orig.length; i < j; i++) {
cur = orig[i];
if (!(cur.type in types)) {
types[cur.type] = {type: cur.type, foods: []};
newArr.push(types[cur.type]);
}
types[cur.type].foods.push(cur.food);
}
return newArr;
}
console.log(transformArr(origArr));
DEMO: http://jsfiddle.net/ErikE/nSLua/3/
Credit goes to @ErikE for improving/reducing my original code to help with redundancy I had :)
Here is a slightly different but more generic version of @Ian's answer
Caveat: the result is slightly different from the OP requirement, but others like me who stumble on this question might benefit from a more generic answer IMHO
var origArr = [
{food: 'apple', type: 'fruit'},
{food: 'potato', type: 'vegetable'},
{food: 'banana', type: 'fruit'}
];
function groupBy(arr, key) {
var newArr = [],
types = {},
newItem, i, j, cur;
for (i = 0, j = arr.length; i < j; i++) {
cur = arr[i];
if (!(cur[key] in types)) {
types[cur[key]] = { type: cur[key], data: [] };
newArr.push(types[cur[key]]);
}
types[cur[key]].data.push(cur);
}
return newArr;
}
console.log(groupBy(origArr, 'type'));
You can find a jsfiddle here
An ES6 solution to this old question:
Iterate using Array#reduce
, and collect the items by group into a Map
. Use spread to convert the Map#values
back into array:
const data = [
{food: 'apple', type: 'fruit'},
{food: 'potato', type: 'vegetable'},
{food: 'banana', type: 'fruit'},
];
const result = [...data.reduce((hash, { food, type }) => {
const current = hash.get(type) || { type, foods: [] };
current.foods.push({ food });
return hash.set(type, current);
}, new Map).values()];
console.log(result);
var foods = [
{food: 'apple', type: 'fruit'},
{food: 'potato', type: 'vegetable'},
{food: 'banana', type: 'fruit'}
];
var newFoods = _.chain( foods ).reduce(function( memo, food ) {
memo[ food.type ] = memo[ food.type ] || [];
memo[ food.type ].push( food.food );
return memo;
}, {}).map(function( foods, type ) {
return {
type: type,
foods: foods
};
}).value();
http://jsbin.com/etaxih/2/edit
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