diff --git a/pkgs/collection/CHANGELOG.md b/pkgs/collection/CHANGELOG.md index 743fddf2..f2acb6b2 100644 --- a/pkgs/collection/CHANGELOG.md +++ b/pkgs/collection/CHANGELOG.md @@ -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` diff --git a/pkgs/collection/lib/src/iterable_extensions.dart b/pkgs/collection/lib/src/iterable_extensions.dart index d9516e67..53f18908 100644 --- a/pkgs/collection/lib/src/iterable_extensions.dart +++ b/pkgs/collection/lib/src/iterable_extensions.dart @@ -613,6 +613,33 @@ extension IterableExtension on Iterable { 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 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. diff --git a/pkgs/collection/test/extensions_test.dart b/pkgs/collection/test/extensions_test.dart index 16878a30..617291d3 100644 --- a/pkgs/collection/test/extensions_test.dart +++ b/pkgs/collection/test/extensions_test.dart @@ -1224,6 +1224,33 @@ void main() { ); }); }); + group('.intersperse', () { + test('empty', () { + expect(iterable([]).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', () {