Skip to content

Instantly share code, notes, and snippets.

@plammens
Last active March 14, 2023 21:01
Show Gist options
  • Save plammens/a2e6882a352a12e681a4a23e7d9f1a69 to your computer and use it in GitHub Desktop.
Save plammens/a2e6882a352a12e681a4a23e7d9f1a69 to your computer and use it in GitHub Desktop.
groupConsecutiveBy
extension MoreIterableTools<E> on Iterable<E> {
/// Group consecutive elements with the same key.
Iterable<MapEntry<K, Iterator<E>>> groupConsecutiveBy<K>(
K Function(E) keyOf,
) sync* {
final iterator = this.iterator;
bool moveNext = iterator.moveNext(), lastGroupConsumed = true;
while (moveNext) {
if (!lastGroupConsumed) {
throw StateError("Can't advance to the next group"
" until the previous group has been fully consumed.");
}
final currentKey = keyOf(iterator.current);
lastGroupConsumed = false;
Iterable<E> makeGroup() sync* {
do {
yield iterator.current;
} while ((moveNext = iterator.moveNext()) &&
keyOf(iterator.current) == currentKey);
lastGroupConsumed = true;
}
yield MapEntry(currentKey, makeGroup().iterator);
}
}
}
List<E> consume<E>(Iterator<E> iterator) {
final result = <E>[];
while (iterator.moveNext()) {
result.add(iterator.current);
}
return result;
}
Iterable<E> generateInfinitely<E>(E Function(int) generator) sync* {
for (int i = 0; true; ++i) {
yield generator(i);
}
}
void main() {
final iterable = generateInfinitely((i) => i);
final groupBy = iterable.groupConsecutiveBy((i) => i ~/ 10).iterator;
groupBy.moveNext();
final group1 = groupBy.current;
final group1Elements = group1.value;
group1Elements.moveNext();
print(group1Elements.current);
print(consume(group1Elements));
groupBy.moveNext();
final group2 = groupBy.current;
final group2Elements = group2.value;
group2Elements.moveNext();
print(consume(group2Elements));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment