I'm having trouble figuring out from the lodash documentation if my assumption about sorting and grouping is correct.
If I use sortBy, then use groupBy, do the arrays produced by groupBy maintain the sort order of items?
For example, say I have the following array:
var testArray = [[5,6],[1,3],[5,4],[5,1]]
And I would like to group these by their first element, but also have them sorted by their second element within these groups. So, in lodash I assume I can do the following:
_.chain(testArray)
.sortBy(function (item) { return item[1]; })
.groupBy(function (item) { return item[0]; })
.value()
Which ends up producing what I would expect it to:
{
1: [[1,3]]
5: [[5,1],[5,4],[5,6]]
}
Is this just coincidence? Is there anything about how sortBy and groupBy work that ensures this ordering of the grouped arrays? The documentation says that sortBy is a stable sort, does that in the same way apply to groupBy? Is there any reason I should not assume this will work every time?
groupBy , but it does preserve the order of array-like collections, and that's probably unlikely to change. So the sub-items within groups would retain their original ordering, but the grouped key ordering may change, because they are object properties.
Lodash helps in working with arrays, collection, strings, objects, numbers etc. The _. sortBy() method creates an array of elements which is sorted in ascending order by the results of running each element in a collection through each iteratee.
It's not. Here's example, where order is not retained:
const data = [
{
item: 'item1',
group: 'g2'
}, {
item: 'item2',
group: 'g3'
}, {
item: 'item3',
group: 'g1'
}, {
item: 'item4',
group: 'g2'
}, {
item: 'item5',
group: 'g3'
}
]
const groupedItems = _(data).groupBy(item => item.group).value()
In this case one would expect that group order would be: g2, g3, g1 - reality is that they are sorted g1, g2, g3.
You can re-sort them with original array though.
const groupedItems = _(data)
.groupBy(item => item.group)
.sortBy(group => data.indexOf(group[0]))
.value()
This will ensure original order of items.
The current implementation of _.groupBy
is:
// An internal function used for aggregate "group by" operations.
var group = function(behavior) {
return function(obj, iteratee, context) {
var result = {};
iteratee = cb(iteratee, context);
_.each(obj, function(value, index) {
var key = iteratee(value, index, obj);
behavior(result, value, key);
});
return result;
};
};
// Groups the object's values by a criterion. Pass either a string attribute
// to group by, or a function that returns the criterion.
_.groupBy = group(function(result, value, key) {
if (_.has(result, key)) result[key].push(value); else result[key] = [value];
});
Basically it iterates through each of the items in the collection in order (if the collection is array-like, which it would be after a sortBy
), and pushes them to an array based on their key value.
So yes, I'm not sure if this is an "official" characteristic of _.groupBy
, but it does preserve the order of array-like collections, and that's probably unlikely to change.
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