I spent hours on the Lo-Dash documentation site now, and can't find a solution for my problem. I don't know how it's called, so it is a bit hard to search for. I basically want to group an array into an object so that duplicate entries are a field while different entries are an array.
For example, I have this array:
var characters = [
{ 'name': 'barney', 'age': 42, 'pet': 'dog' },
{ 'name': 'fred', 'age': 35, 'pet': 'dog' },
{ 'name': 'barney', 'age': 42, 'pet': 'cat' },
{ 'name': 'fred', 'age': 35, 'pet': 'goldfish' }
];
And I want to get this:
[
{ name: 'barney',
age: 42,
pet: [ 'dog', 'cat' ] },
{ name: 'fred',
age: 35,
pet: [ 'dog', 'goldfish' ] }
]
Is there a Lo-Dash method for doing this, or do I have to chain several ones? What is the best way to achieve this?
The group() method groups the elements of the calling array according to the string values returned by a provided testing function. The returned object has separate properties for each group, containing arrays with the elements in the group.
If both arrays are in the correct order; where each item corresponds to its associated member identifier then you can simply use. var merge = _. merge(arr1, arr2);
The _. get() function is an inbuilt function in the Underscore. js library of JavaScript which is used to get the value at the path of object. If the resolved value is undefined, the defaultValue is returned in its place. Syntax: _.get(object, path, [defaultValue])
Although answered, still a try. JSFIDDLE
var characters = [
{ 'name': 'barney', 'age': 42, 'pet': 'dog' },
{ 'name': 'fred', 'age': 35, 'pet': 'dog' },
{ 'name': 'barney', 'age': 42, 'pet': 'cat' },
{ 'name': 'fred', 'age': 35, 'pet': 'goldfish' }
];
var result=_.chain(characters).groupBy("name").map(function(v, i) {
return {
name: i,
age: _.get(_.find(v, 'age'), 'age'),
pet: _.map(v, 'pet')
}
}).value();
document.body.innerHTML = '<pre>' + JSON.stringify(result, null, ' ') + '</pre>';
Here a more lo-dash, underscore way of doing it:
var result = _.reduce(characters, function (prev, current) {
var char = _.find(prev, function (character) {
return character['name'] === current['name'];
});
// Character does not yet exists in the array, push it
if (char === undefined) {
prev.push(current);
} else {
// If char['pet'] is not an array, create one
if (!_.isArray(char['pet'])) {
char['pet'] = [char['pet']];
}
// Push the current pets to the founded character
char['pet'].push(current['pet']);
}
return prev;
}, []); // Initialize an empty array for the prev object
console.log(result);
Let me know if there is a more awesomeness feature in underscore/lodash :-)!
Here's a more elegant and much shorter solution, with chaining:
var characters = [{
'name': 'barney',
'age': 42,
'pet': 'dog'
}, {
'name': 'fred',
'age': 35,
'pet': 'dog'
}, {
'name': 'barney',
'age': 42,
'pet': 'cat'
}, {
'name': 'fred',
'age': 35,
'pet': 'fish'
}];
var result = _(characters).groupBy('name').transform(function(result, current) {
result.push({
name: current[0].name,
age: current[0].age,
pets: _.map(current, 'pet')
});
}, []).value();
document.write('<pre>' + JSON.stringify(result, null, '\t') + '</pre>');
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
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