Skip to content

Commit 88be07a

Browse files
author
Tim Vermeulen
committed
Rename types to include a Sequence or Collection suffix, and clean up some guides
1 parent 9f62800 commit 88be07a

32 files changed

+510
-440
lines changed

Guides/AdjacentPairs.md

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55

66
Lazily iterates over tuples of adjacent elements.
77

8-
This operation is available for any sequence by calling the `adjacentPairs()` method.
8+
This operation is available for any sequence by calling the `adjacentPairs()`
9+
method.
910

1011
```swift
1112
let numbers = (1...5)
@@ -15,38 +16,48 @@ let pairs = numbers.adjacentPairs()
1516

1617
## Detailed Design
1718

18-
The `adjacentPairs()` method is declared as a `Sequence` extension returning `AdjacentPairsSequence` and as a `Collection` extension returning `AdjacentPairsCollection`.
19+
The `adjacentPairs()` method is declared as a `Sequence` extension returning
20+
`AdjacentPairsSequence` and as a `Collection` extension returning
21+
`AdjacentPairsCollection`.
1922

2023
```swift
2124
extension Sequence {
22-
public func adjacentPairs() -> AdjacentPairsSequence<Self>
25+
public func adjacentPairs() -> AdjacentPairsSequence<Self>
2326
}
2427
```
2528

2629
```swift
2730
extension Collection {
28-
public func adjacentPairs() -> AdjacentPairsCollection<Self>
31+
public func adjacentPairs() -> AdjacentPairsCollection<Self>
2932
}
3033
```
3134

32-
The `AdjacentPairsSequence` type is a sequence, and the `AdjacentPairsCollection` type is a collection with conditional conformance to `BidirectionalCollection` and `RandomAccessCollection` when the underlying collection conforms.
35+
The `AdjacentPairsSequence` type is a sequence, and the
36+
`AdjacentPairsCollection` type is a collection with conditional conformance to
37+
`BidirectionalCollection` and `RandomAccessCollection` when the underlying
38+
collection conforms.
3339

3440
### Complexity
3541

3642
Calling `adjacentPairs` is an O(1) operation.
3743

3844
### Naming
3945

40-
This method is named for clarity while remaining agnostic to any particular domain of programming. In natural language processing, this operation is akin to computing a list of bigrams; however, this algorithm is not specific to this use case.
41-
42-
[naming]: https://forums.swift.org/t/naming-of-chained-with/40999/
46+
This method is named for clarity while remaining agnostic to any particular
47+
domain of programming. In natural language processing, this operation is akin to
48+
computing a list of bigrams; however, this algorithm is not specific to this use
49+
case.
4350

4451
### Comparison with other languages
4552

46-
This function is often written as a `zip` of a sequence together with itself, minus its first element.
53+
This function is often written as a `zip` of a sequence together with itself,
54+
minus its first element.
4755

4856
**Haskell:** This operation is spelled ``s `zip` tail s``.
4957

50-
**Python:** Python users may write `zip(s, s[1:])` for a list with at least one element. For natural language processing, the `nltk` package offers a `bigrams` function akin to this method.
58+
**Python:** Python users may write `zip(s, s[1:])` for a list with at least one
59+
element. For natural language processing, the `nltk` package offers a `bigrams`
60+
function akin to this method.
5161

52-
Note that in Swift, the spelling `zip(s, s.dropFirst())` is undefined behavior for a single-pass sequence `s`.
62+
Note that in Swift, the spelling `zip(s, s.dropFirst())` is undefined behavior
63+
for a single-pass sequence `s`.

Guides/Chain.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@ the shared conformances of the two underlying types.
2525
The `chain(_:_:)` function takes two sequences as arguments:
2626

2727
```swift
28-
public func chain<S1, S2>(_ s1: S1, _ s2: S2) -> Chain2<S1, S2>
28+
public func chain<S1, S2>(_ s1: S1, _ s2: S2) -> Chain2Sequence<S1, S2>
2929
where S1.Element == S2.Element
3030
```
3131

32-
The resulting `Chain2` type is a sequence, with conditional conformance to
33-
`Collection`, `BidirectionalCollection`, and `RandomAccessCollection` when both
34-
the first and second arguments conform.
32+
The resulting `Chain2Sequence` type is a sequence, with conditional conformance
33+
to `Collection`, `BidirectionalCollection`, and `RandomAccessCollection` when
34+
both the first and second arguments conform.
3535

3636
### Naming
3737

Guides/Chunked.md

Lines changed: 46 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/ChunkedTests.swift)]
55

66
Break a collection into subsequences where consecutive elements pass a binary
7-
predicate, or where all elements in each chunk project to the same value.
7+
predicate, or where all elements in each chunk project to the same value.
88

9-
Also, includes a `chunks(ofCount:)` that breaks a collection into subsequences
9+
Also includes a `chunks(ofCount:)` that breaks a collection into subsequences
1010
of a given `count`.
1111

1212
There are two variations of the `chunked` method: `chunked(by:)` and
@@ -20,22 +20,22 @@ let chunks = numbers.chunked(by: { $0 <= $1 })
2020
// [[10, 20, 30], [10, 40, 40], [10, 20]]
2121
```
2222

23-
The `chunk(on:)` method, by contrast, takes a projection of each element and
23+
The `chunked(on:)` method, by contrast, takes a projection of each element and
2424
separates chunks where the projection of two consecutive elements is not equal.
25-
The result includes both the projected value and the subsequence
26-
that groups elements with that projected value:
25+
The result includes both the projected value and the subsequence that groups
26+
elements with that projected value:
2727

2828
```swift
2929
let names = ["David", "Kyle", "Karoy", "Nate"]
3030
let chunks = names.chunked(on: \.first!)
3131
// [("D", ["David"]), ("K", ["Kyle", "Karoy"]), ("N", ["Nate"])]
3232
```
3333

34-
The `chunks(ofCount:)` method takes a `count` parameter (greater than zero)
35-
and separates the collection into chunks of this given count.
36-
If the `count` parameter is evenly divided by the count of the base `Collection`,
37-
all the chunks will have a count equal to the parameter.
38-
Otherwise, the last chunk will contain the remaining elements.
34+
The `chunks(ofCount:)` method takes a `count` parameter (greater than zero)
35+
and separates the collection into chunks of this given count. If the `count`
36+
parameter is evenly divided by the count of the base `Collection`, all the
37+
chunks will have a count equal to the parameter. Otherwise, the last chunk will
38+
contain the remaining elements.
3939

4040
```swift
4141
let names = ["David", "Kyle", "Karoy", "Nate"]
@@ -46,11 +46,11 @@ let remaining = names.chunks(ofCount: 3)
4646
// equivalent to [["David", "Kyle", "Karoy"], ["Nate"]]
4747
```
4848

49-
The `chunks(ofCount:)` is the subject of an [existing SE proposal][proposal].
49+
The `chunks(ofCount:)` is the subject of an [existing SE proposal][proposal].
5050

51-
When "chunking" a collection, the entire collection is included in the result,
51+
When "chunking" a collection, the entire collection is included in the result,
5252
unlike the `split` family of methods, where separators are dropped.
53-
Joining the result of a chunking method call recreates the original collection.
53+
Joining the result of a chunking method call recreates the original collection.
5454

5555
```swift
5656
c.elementsEqual(c.chunked(...).joined())
@@ -66,41 +66,49 @@ versions that return a lazy wrapper added to `LazyCollectionProtocol`.
6666

6767
```swift
6868
extension Collection {
69-
public func chunked(
70-
by belongInSameGroup: (Element, Element) -> Bool
71-
) -> [SubSequence]
72-
73-
public func chunked<Subject: Equatable>(
74-
on projection: (Element) -> Subject
75-
) -> [(Subject, SubSequence)]
76-
}
77-
78-
extension LazyCollectionProtocol {
79-
public func chunked(
80-
by belongInSameGroup: @escaping (Element, Element) -> Bool
81-
) -> ChunkedBy<Elements, Element>
82-
83-
public func chunked<Subject: Equatable>(
84-
on projection: @escaping (Element) -> Subject
85-
) -> ChunkedOn<Elements, Subject>
69+
public func chunked(
70+
by belongInSameGroup: (Element, Element) -> Bool
71+
) -> [SubSequence]
72+
73+
public func chunked<Subject: Equatable>(
74+
on projection: (Element) -> Subject
75+
) -> [(Subject, SubSequence)]
76+
}
77+
78+
extension LazyCollectionProtocol {
79+
public func chunked(
80+
by belongInSameGroup: @escaping (Element, Element) -> Bool
81+
) -> ChunkedByCollection<Elements, Element>
82+
83+
public func chunked<Subject: Equatable>(
84+
on projection: @escaping (Element) -> Subject
85+
) -> ChunkedOnCollection<Elements, Subject>
8686
}
8787
```
8888

89-
The `ChunkedBy` and `ChunkedOn` types are bidirectional when the wrapped collection is
90-
bidirectional.
89+
The `ChunkedByCollection` and `ChunkedOnCollection` types are bidirectional when
90+
the wrapped collection is bidirectional.
9191

9292
### Complexity
9393

9494
The eager methods are O(_n_), the lazy methods are O(_1_).
9595

9696
### Naming
9797

98-
The operation performed by these methods is similar to other ways of breaking a collection up into subsequences. In particular, the predicate-based `split(where:)` method looks similar to `chunked(on:)`. You can draw a distinction between these different operations based on the resulting subsequences:
99-
100-
- `split`: *In the standard library.* Breaks a collection into subsequences, removing any elements that are considered "separators". The original collection cannot be recovered from the result of splitting.
101-
- `chunked`: *In this package.* Breaks a collection into subsequences, preserving each element in its initial ordering. Joining the resulting subsequences re-forms the original collection.
102-
- `sliced`: *Not included in this package or the stdlib.* Breaks a collection into potentially overlapping subsequences.
103-
98+
The operation performed by these methods is similar to other ways of breaking a
99+
collection up into subsequences. In particular, the predicate-based
100+
`split(where:)` method looks similar to `chunked(on:)`. You can draw a
101+
distinction between these different operations based on the resulting
102+
subsequences:
103+
104+
- `split`: *In the standard library.* Breaks a collection into subsequences,
105+
removing any elements that are considered "separators". The original collection
106+
cannot be recovered from the result of splitting.
107+
- `chunked`: *In this package.* Breaks a collection into subsequences,
108+
preserving each element in its initial ordering. Joining the resulting
109+
subsequences re-forms the original collection.
110+
- `sliced`: *Not included in this package or the stdlib.* Breaks a collection
111+
into potentially overlapping subsequences.
104112

105113
### Comparison with other languages
106114

Guides/Combinations.md

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,27 +60,28 @@ for combo in numbers.combinations(ofCount: 2...3) {
6060
## Detailed Design
6161

6262
The `combinations(ofCount:)` method is declared as a `Collection` extension,
63-
and returns a `Combinations` type:
63+
and returns a `CombinationsSequence` type:
6464

6565
```swift
6666
extension Collection {
67-
public func combinations(ofCount k: Int) -> Combinations<Self>
67+
public func combinations(ofCount k: Int) -> CombinationsSequence<Self>
6868
}
6969
```
7070

71-
Since the `Combinations` type needs to store an array of the collection’s
72-
indices and mutate the array to generate each permutation, `Combinations` only
73-
has `Sequence` conformance. Adding `Collection` conformance would require
74-
storing the array in the index type, which would in turn lead to copying the
75-
array at every index advancement. `Combinations` does conform to
76-
`LazySequenceProtocol` when the base type conforms.
71+
Since the `CombinationsSequence` type needs to store an array of the
72+
collection’s indices and mutate the array to generate each permutation,
73+
`CombinationsSequence` only has `Sequence` conformance. Adding `Collection`
74+
conformance would require storing the array in the index type, which would in
75+
turn lead to copying the array at every index advancement.
76+
`CombinationsSequence` does conform to `LazySequenceProtocol` when the base type
77+
conforms.
7778

7879
### Complexity
7980

8081
Calling `combinations(ofCount:)` accesses the count of the collection, so it’s
8182
an O(1) operation for random-access collections, or an O(_n_) operation
82-
otherwise. Creating the iterator for a `Combinations` instance and each call to
83-
`Combinations.Iterator.next()` is an O(_n_) operation.
83+
otherwise. Creating the iterator for a `CombinationsSequence` instance and each
84+
call to `CombinationsSequence.Iterator.next()` is an O(_n_) operation.
8485

8586
### Naming
8687

Guides/Cycle.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,20 @@ Two new methods are added to collections:
2626

2727
```swift
2828
extension Collection {
29-
func cycled() -> Cycle<Self>
29+
func cycled() -> CycledSequence<Self>
3030

31-
func cycled(times: Int) -> FiniteCycle<Self>
31+
func cycled(times: Int) -> CycledTimesCollection<Self>
3232
}
3333
```
3434

35-
The new `Cycle` type is a sequence only, given that the `Collection` protocol
36-
design makes infinitely large types impossible/impractical. `Cycle` also
37-
conforms to `LazySequenceProtocol` when the base type conforms.
35+
The new `CycledSequence` type is a sequence only, given that the `Collection`
36+
protocol design makes infinitely large types impossible/impractical.
37+
`CycledSequence` also conforms to `LazySequenceProtocol` when the base type
38+
conforms.
3839

39-
The `FiniteCycle` type always has `Collection` conformance, with
40-
`BidirectionalCollection` conformance
41-
when called on a bidirectional collection. `FiniteCycle` also
42-
conforms to `LazyCollectionProtocol` when the base type conforms.
40+
The `CycledTimesCollection` type always has `Collection` conformance, with
41+
`BidirectionalCollection`, `RandomAccessCollection`, and `LazySequenceProtocol`
42+
conformance when the base type conforms.
4343

4444
### Complexity
4545

Guides/Indexed.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ The `indexed` method returns an `Indexed` type:
2525

2626
```swift
2727
extension Collection {
28-
func indexed() -> Indexed<Self>
28+
func indexed() -> IndexedCollection<Self>
2929
}
3030
```
3131

32-
`Indexed` scales from a collection up to a random-access collection, depending on
33-
its base type. `Indexed` also conforms to `LazySequenceProtocol` and
34-
`LazyCollectionProtocol` when the base type conforms.
32+
`IndexedCollection` scales from a collection up to a random-access collection,
33+
depending on its base type. `Indexed` also conforms to `LazySequenceProtocol`
34+
and `LazyCollectionProtocol` when the base type conforms.
3535

Guides/Intersperse.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ A new method is added to sequence:
2525

2626
```swift
2727
extension Sequence {
28-
func interspersed(with separator: Element) -> Intersperse<Self>
28+
func interspersed(with separator: Element) -> InterspersedSequence<Self>
2929
}
3030
```
3131

32-
The new `Intersperse` type represents the sequence when the separator is
33-
inserted between each element. `Intersperse` conforms to `Collection`,
34-
`BidirectionalCollection`, `RandomAccessCollection`, `LazySequenceProtocol` and
35-
`LazyCollectionProtocol` when the base sequence conforms to those respective
36-
protocols.
32+
The new `InterspersedSequence` type represents the sequence when the separator
33+
is inserted between each element. `InterspersedSequence` conforms to
34+
`Collection`, `BidirectionalCollection`, `RandomAccessCollection`,
35+
`LazySequenceProtocol` and `LazyCollectionProtocol` when the base sequence
36+
conforms to those respective protocols.
3737

3838
### Complexity
3939

Guides/LazySplit.md

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ collection without allocating additional storage on the heap.
1515
// Splitting a lazy sequence.
1616
let numbers = stride(from: 1, through: 16, by: 1)
1717
for subsequence in numbers.lazy.split(
18-
whereSeparator: { $0 % 3 == 0 || $0 % 5 == 0 }
18+
whereSeparator: { $0 % 3 == 0 || $0 % 5 == 0 }
1919
) {
20-
print(subsequence)
20+
print(subsequence)
2121
}
2222
/* Prints:
2323
[1, 2]
@@ -31,7 +31,7 @@ for subsequence in numbers.lazy.split(
3131
// Splitting a lazy collection.
3232
let line = "BLANCHE: I don't want realism. I want magic!"
3333
for subsequence in line.lazy.split(separator: " ") {
34-
print(subsequence)
34+
print(subsequence)
3535
}
3636
/* Prints
3737
BLANCHE:
@@ -52,29 +52,28 @@ magic!
5252
`split(separator:maxSplits:omittingEmptySubsequences:)`.
5353

5454
The `LazySequence` versions of those methods return an instance of
55-
`LazySplitSequence`. The `LazyCollection` versions return an instance of
56-
`LazySplitCollection`.
55+
`SplitSequence`. The `LazyCollection` versions return an instance of
56+
`SplitCollection`.
5757

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.
58+
`SplitSequence` wraps the sequence to be split, and provides an iterator whose
59+
`next` method returns a newly-allocated array containing the elements of each
60+
subsequence in the split sequence in turn.
6161

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.
62+
`SplitCollection` wraps the collection to be split. Its `Index` wraps a range of
63+
base collection indices. `startIndex` is computed at initialization.
64+
Subscripting a `SplitCollection` instance returns the slice of the original
65+
collection which is the subsequence of the split collection at the given index's
66+
position.
6767

6868
### Complexity
6969

70-
Iterating a `LazySplitSequence` instance is O(_n_) in time and space,
71-
since each subsequence returned is a newly-allocated array.
70+
Iterating a `SplitSequence` instance is O(_n_) in time and space, since each
71+
subsequence returned is a newly-allocated array.
7272

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).
73+
Iterating a `SplitCollection` instance is O(_n_) in time and O(1) in space,
74+
since each subsequence returned is a slice of the base collection. Since
75+
`startIndex` is computed at initialization, some or all of the time cost may be
76+
paid at initialization. For example, if the base collection contains no elements
77+
determined to be separators, it will be iterated entirely on initialization of
78+
the split collection, and all subsequent operations on the split collection,
79+
such as `index(after:)`, will have complexity O(1).

0 commit comments

Comments
 (0)