Reputation: 14228
I have an array like this:
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'},
{name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'},
{name: 'Server 5', country: 'US'}];
What I want is group and count
to get the ouput like below:
[
{
"country": "DE",
"count": 2
},
{
"country": "PL",
"count": 1
},
{
"country": "US",
"count": 2
}
]
Currently, I'm using lodash
but I think there are better ways (for example, using _groupBy
or something like that) to resolve it, right?
My code is here:
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
const objectGroupby = _.countBy(arr, 'country');
const result = Object.entries(objectGroupby).map(([key, value]) => ({country: key, count: value}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
As you can see, _.countBy(arr, 'country')
just returns an object instead of an array.
{
"DE": 2,
"PL": 1,
"US": 2
}
Then I have to use Object.entries()
& map
to resolve it.
Upvotes: 1
Views: 169
Reputation: 14228
Hooray !!!
After researching in recent days, I finally figure out the solution using groupBy
like this.
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
const result = _(arr).groupBy(x => x.country)
.map((value, key) => ({country: key, count: value.length}));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Explain:
country
propertykey
is the group's name (country), value
is the array of objects.Reference resource:
Upvotes: 0
Reputation: 5054
In terms of performance i think I can write a more performant code using simple for loops as for loops are faster than .map(), .reduce() etc.
You can do the following by traversing the original array once,
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
let mapObj = {};
let res = [];
let resIndex = 0;
for(let i = 0; i < arr.length; i++) {
if(mapObj[arr[i].country] >= 0) {
res[mapObj[arr[i].country]].count++;
} else {
res.push({country: arr[i].country, count: 1});
mapObj[arr[i].country] = resIndex;
resIndex++;
}
}
console.log(res);
In terms of elegant or more readable code, I think using a reduce is more readable. But readability is subjective, it varies from person to person. For me reduce would be more readable.
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
res = arr.reduce((prev, curr) => {
const index = prev.findIndex(item => item.country === curr.country);
if(index > -1) {
prev[index].count++;
} else {
prev.push({ country: curr.country, count: 1});
}
return prev;
}, []);
console.log(res);
Update: Using Lodash,
const arr = [ {name: 'Server 1', country: 'DE'}, {name: 'Server 2', country: 'PL'}, {name: 'Server 3', country: 'US'}, {name: 'Server 4', country: 'DE'}, {name: 'Server 5', country: 'US'}];
result = _.reduce(_.countBy(arr, 'country'), (result, value, key) => {
result.push({ country: key, count: value});
return result;
}, []);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
Upvotes: 1