Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkgs/collection/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## 1.20.0-wip

- Add `intersperse` method to `IterableExtension` for efficient element separation.
- Add `IterableMapEntryExtension` for working on `Map` as a list of pairs, using
`Map.entries`.
- Explicitly mark `BoolList` as `abstract interface`
Expand Down
27 changes: 27 additions & 0 deletions pkgs/collection/lib/src/iterable_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -613,6 +613,33 @@ extension IterableExtension<T> on Iterable<T> {
yield slice;
}
}

/// Lazily returns a new iterable where a [separator] is placed between each
/// element of this iterable.
///
/// This is the most performant way to implement this functionality because
/// it uses a generator (`sync*`) and does not create a new list upfront,
/// making it memory-efficient for iterables of any size.
///
/// Example:
/// ```dart
/// final numbers = [1, 2, 3];
/// final withSeparators = numbers.intersperse(0);
/// print(withSeparators.toList()); // Output: [1, 0, 2, 0, 3]
/// ```
///
/// The resulting iterable is lazy. It only computes the next value when
/// it's requested.
Iterable<T> intersperse(T separator) sync* {
final iterator = this.iterator;
if (iterator.moveNext()) {
yield iterator.current;
while (iterator.moveNext()) {
yield separator;
yield iterator.current;
}
}
}
}

/// Extensions that apply to iterables with a nullable element type.
Expand Down
27 changes: 27 additions & 0 deletions pkgs/collection/test/extensions_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1224,6 +1224,33 @@ void main() {
);
});
});
group('.intersperse', () {
test('empty', () {
expect(iterable(<int>[]).intersperse(0), []);
});
test('single element', () {
expect(iterable([1]).intersperse(0), [1]);
});
test('two elements', () {
expect(iterable([1, 2]).intersperse(0), [1, 0, 2]);
});
test('multiple elements', () {
expect(iterable([1, 2, 3, 4]).intersperse(0), [1, 0, 2, 0, 3, 0, 4]);
});
test('with different separator types', () {
expect(iterable(['a', 'b', 'c']).intersperse('-'),
['a', '-', 'b', '-', 'c']);
expect(iterable([1.5, 2.5, 3.5]).intersperse(0.0),
[1.5, 0.0, 2.5, 0.0, 3.5]);
});
test('with nullable int separator', () {
expect(iterable([1, 2, 3]).intersperse(0), [1, 0, 2, 0, 3]);
});
test('with empty string separator', () {
expect(iterable(['a', 'b', 'c']).intersperse(''),
['a', '', 'b', '', 'c']);
});
});
});
group('of MapEntry', () {
group('.whereKey', () {
Expand Down