First time posting a question and answering myself immediately. Figured someone else might need to do this, and I like to save this for future reference.
Inspired by this C# solution, I wrote the following underscore.js mixin:
_.mixin({
groupByAdjacent: (list, iteratee) => {
let i = 0;
let length = 0;
const groupList = [];
let group = [list[0]];
let pred = list[0];
for (i = 1, length = list.length; i < length; i++) {
if (iteratee(pred, list[i])) {
group.push(list[i]);
} else {
groupList.push(group);
group = [list[i]];
}
pred = list[i];
}
groupList.push(group);
return groupList;
},
});
Usage like this:
const numbers = [1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18];
const groupsOfNumbers = _.groupByAdjacent(numbers, (x, y) => {
return ((parseInt(x, 10) + 1) == parseInt(y, 10))
});
console.log(groupsOfNumbers);
Or if you need to group objects with the consecutive numbers in a property we can also group the objects:
const numbersInObjects = [{ n: 1 }, { n: 2 }, { n: 3 }, { n: 4 }, { n: 7 }, { n: 8 }, { n: 11 }, { n: 15 }, { n: 16 }, { n: 17 }, { n: 18 }];
const groupsOfNumbersInObjects = _.groupByAdjacent(numbersInObjects, (x, y) => {
return ((parseInt(x.n, 10) + 1) == parseInt(y.n, 10))
});
If anyone can make this shorter, that'd be great! I hope to get rid of the for loop but I need to skip the first item so _.each
doesn't work.