Skip to content

Commit e7c6716

Browse files
authored
Add lazy split implementation. (#78)
`split(maxSplits:omittingEmptySubsequences:whereSeparator:)` and `split(separator:maxSplits:omittingEmptySubsequences:)` now operate lazily when called on `LazySequenceProtocol`- or `LazyCollectionProtocol`-conforming values. In the latter case, no additional storage is allocated on the heap.
1 parent d2546b8 commit e7c6716

File tree

4 files changed

+1671
-0
lines changed

4 files changed

+1671
-0
lines changed

Guides/LazySplit.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# LazySplit
2+
3+
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/LazySplit.swift) |
4+
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/LazySplitTests.swift)]
5+
6+
Lazily-evaluating versions of
7+
[`split(maxSplits:omittingEmptySubsequences:whereSeparator:)`](https://developer.apple.com/documentation/swift/sequence/3128814-split)
8+
and [`split(separator:maxSplits:omittingEmptySubsequences:)`](https://developer.apple.com/documentation/swift/sequence/3128818-split),
9+
performing the same operation as their counterparts defined on
10+
`Sequence` and `Collection`, are added to `LazySequence` and
11+
`LazyCollection`. The `LazyCollection` methods allow splitting a
12+
collection without allocating additional storage on the heap.
13+
14+
```swift
15+
// Splitting a lazy sequence.
16+
let numbers = stride(from: 1, through: 16, by: 1)
17+
for subsequence in numbers.lazy.split(
18+
whereSeparator: { $0 % 3 == 0 || $0 % 5 == 0 }
19+
) {
20+
print(subsequence)
21+
}
22+
/* Prints:
23+
[1, 2]
24+
[4]
25+
[7, 8]
26+
[11]
27+
[13, 14]
28+
[16]
29+
*/
30+
31+
// Splitting a lazy collection.
32+
let line = "BLANCHE: I don't want realism. I want magic!"
33+
for subsequence in line.lazy.split(separator: " ") {
34+
print(subsequence)
35+
}
36+
/* Prints
37+
BLANCHE:
38+
I
39+
don't
40+
want
41+
realism.
42+
I
43+
want
44+
magic!
45+
*/
46+
```
47+
48+
## Detailed Design
49+
50+
`LazySequence` and `LazyCollection` are each extended with
51+
`split(maxSplits:omittingEmptySubsequences:whereSeparator:)` and
52+
`split(separator:maxSplits:omittingEmptySubsequences:)`.
53+
54+
The `LazySequence` versions of those methods return an instance of
55+
`LazySplitSequence`. The `LazyCollection` versions return an instance of
56+
`LazySplitCollection`.
57+
58+
`LazySplitSequence` wraps the sequence to be split, and provides an
59+
iterator whose `next` method returns a newly-allocated array containing
60+
the elements of each subsequence in the split sequence in turn.
61+
62+
`LazySplitCollection` wraps the collection to be split. Its `Index`
63+
wraps a range of base collection indices. `startIndex` is computed at
64+
initialization. Subscripting a `LazySplitCollection` instance returns
65+
the slice of the original collection which is the subsequence of the
66+
split collection at the given index's position.
67+
68+
### Complexity
69+
70+
Iterating a `LazySplitSequence` instance is O(_n_) in time and space,
71+
since each subsequence returned is a newly-allocated array.
72+
73+
Iterating a `LazySplitCollection` instance is O(_n_) in time and O(1) in
74+
space, since each subsequence returned is a slice of the base
75+
collection. Since `startIndex` is computed at initialization, some or
76+
all of the time cost may be paid at initialization. For example, if the
77+
base collection contains no elements determined to be separators, it
78+
will be iterated entirely on initialization of the split collection, and
79+
all subsequent operations on the split collection, such as
80+
`index(after:)`, will have complexity O(1).

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ Read more about the package, and the intent behind it, in the [announcement on s
4141
- [`trimming(while:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Trim.md): Returns a slice by trimming elements from a collection's start and end.
4242
- [`windows(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Windows.md): Breaks a collection into overlapping subsequences where elements are slices from the original collection.
4343
- [`striding(by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Stride.md): Returns every nth element of a collection.
44+
- [`split(maxSplits:omittingEmptySubsequences:whereSeparator)`, `split(separator:maxSplits:omittingEmptySubsequences)`](https://github.com/apple/swift-algorithms/blob/main/Guides/LazySplit.md): Lazy versions of the Standard Library's eager operations that split sequences and collections into subsequences separated by the specified separator element.
4445

4546
## Adding Swift Algorithms as a Dependency
4647

0 commit comments

Comments
 (0)