Skip to content

Commit 88d0450

Browse files
author
Tim Vermeulen
committed
Add docs
1 parent 081f64f commit 88d0450

File tree

2 files changed

+67
-25
lines changed

2 files changed

+67
-25
lines changed

Guides/Chunked.md

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,24 @@
33
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/Chunked.swift) |
44
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/ChunkedTests.swift)]
55

6-
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.
6+
Break a collection into nonoverlapping subsequences:
87

9-
Also, includes a `chunks(ofCount:)` that breaks a collection into subsequences
10-
of a given `count`.
8+
* `chunked(by:)` forms chunks of consecutive elements that pass a binary predicate,
9+
* `chunked(on:)` forms chunks of consecutive elements that project to equal values,
10+
* `chunks(ofCount:)` forms chunks of a given size, and
11+
* `evenlyChunked(into:)` forms a given number of equally-sized chunks.
1112

12-
There are two variations of the `chunked` method: `chunked(by:)` and
13-
`chunked(on:)`. `chunked(by:)` uses a binary predicate to test consecutive
14-
elements, separating chunks where the predicate returns `false`. For example,
15-
you can chunk a collection into ascending sequences using this method:
13+
`chunked(by:)` uses a binary predicate to test consecutive elements, separating
14+
chunks where the predicate returns `false`. For example, you can chunk a
15+
collection into ascending sequences using this method:
1616

1717
```swift
1818
let numbers = [10, 20, 30, 10, 40, 40, 10, 20]
1919
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.
2525

2626
```swift
@@ -29,11 +29,10 @@ let chunks = names.chunked(on: \.first!)
2929
// [["David"], ["Kyle", "Karoy"], ["Nate"]]
3030
```
3131

32-
The `chunks(ofCount:)` takes a `count` parameter (required to be > 0) and separates
33-
the collection into `n` chunks of this given count. If the `count` parameter is
34-
evenly divided by the count of the base `Collection` all the chunks will have
35-
the count equals to the parameter. Otherwise, the last chunk will contain the
36-
remaining elements.
32+
The `chunks(ofCount:)` method takes a `count` parameter (required to be > 0) and
33+
separates the collection into chunks of this given count. If the length of the
34+
collection is a multiple of the `count` parameter, all chunks will have the
35+
specified size. Otherwise, the last chunk will contain the remaining elements.
3736

3837
```swift
3938
let names = ["David", "Kyle", "Karoy", "Nate"]
@@ -44,7 +43,22 @@ let remaining = names.chunks(ofCount: 3)
4443
// equivalent to [["David", "Kyle", "Karoy"], ["Nate"]]
4544
```
4645

47-
The `chunks(ofCount:)` is the method of the [existing SE proposal][proposal].
46+
The `chunks(ofCount:)` method was previously [proposed](proposal) for inclusion
47+
in the standard library.
48+
49+
The `evenlyChunked(into:)` method takes a `count` parameter and divides the
50+
collection into `count` number of equally-sized chunks. If the length of the
51+
collection is not a multiple of the `count` parameter, the chunks at the start
52+
will be longer than the chunks at the end.
53+
54+
```swift
55+
let evenChunks = (0..<15).evenlyChunked(into: 3)
56+
// equivalent to [0..<5, 5..<10, 10..<15]
57+
58+
let nearlyEvenChunks = (0..<15).evenlyChunked(into: 4)
59+
// equivalent to [0..<4, 4..<8, 8..<12, 12..<15]
60+
```
61+
4862
Unlike the `split` family of methods, the entire collection is included in the
4963
chunked result — joining the resulting chunks recreates the original collection.
5064

@@ -53,14 +67,13 @@ c.elementsEqual(c.chunked(...).joined())
5367
// true
5468
```
5569

56-
Check the [proposal][proposal] detailed design section for more info.
57-
5870
[proposal]: https://github.com/apple/swift-evolution/pull/935
5971

6072
## Detailed Design
6173

62-
The two methods are added as extension to `Collection`, with two matching
63-
versions that return a lazy wrapper added to `LazyCollectionProtocol`.
74+
The four methods are added to `Collection`, with matching versions of
75+
`chunked(by:)` and `chunked(on:)` that return a lazy wrapper added to
76+
`LazyCollectionProtocol`.
6477

6578
```swift
6679
extension Collection {
@@ -71,9 +84,14 @@ extension Collection {
7184
public func chunked<Subject: Equatable>(
7285
on projection: (Element) -> Subject
7386
) -> [SubSequence]
87+
88+
public func chunks(ofCount count: Int) -> ChunkedByCount<Self>
89+
90+
public func evenlyChunked(into count: Int) -> EvenChunks<Self>
7491
}
92+
}
7593

76-
extension LazyCollectionProtocol {
94+
extension LazyCollectionProtocol {
7795
public func chunked(
7896
by belongInSameGroup: @escaping (Element, Element) -> Bool
7997
) -> Chunked<Elements>
@@ -83,9 +101,18 @@ extension Collection {
83101
) -> Chunked<Elements>
84102
}
85103
```
104+
--------------------------------------------------------------------------------
105+
The `Chunked` type conforms to `LazyCollectionProtocol` and also conforms to
106+
`BidirectionalCollection` when the base collection conforms.
107+
108+
The `ChunkedByCount` type conforms to `Collection` and also conforms to both
109+
`BidirectionalCollection` and `RandomAccessCollection` when the base collection
110+
is random-access, as well as to `LazyCollectionProtocol` when the base
111+
collection conforms.
86112

87-
The `Chunked` type is bidirectional when the wrapped collection is
88-
bidirectional.
113+
The `EvenChunks` type conforms to `Collection` and also
114+
conforms to `BidirectionalCollection`, `RandomAccessCollection`, and
115+
`LazyCollectionProtocol` when the base collection conforms..
89116

90117
### Complexity
91118

@@ -105,5 +132,5 @@ The operation performed by these methods is similar to other ways of breaking a
105132
**Ruby:** Ruby’s `Enumerable` class defines `chunk_while` and `chunk`, which map
106133
to the proposed `chunked(by:)` and `chunked(on:)` methods.
107134

108-
**Rust:** Rust defines a variety of size-based `chunks` methods, but doesn’t
109-
include any with the functionality described here.
135+
**Rust:** Rust defines a variety of size-based `chunks` methods, of which the
136+
standard version corresponds to the `chunks(ofCount:)` method defined here.

Sources/Algorithms/Chunked.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,22 @@ extension Collection {
764764
/// Returns a collection of `count` evenly divided subsequences of this
765765
/// collection.
766766
///
767-
/// - Complexity: TODO
767+
/// This method divides the collection into a given number of equally sized
768+
/// chunks. If the length of the collection is not divisible by `count`, the
769+
/// chunks at the start will be longer than the chunks at the end, like in
770+
/// this example:
771+
///
772+
/// for chunk in "Hello, world!".evenlyChunked(into: 5) {
773+
/// print(chunk)
774+
/// }
775+
/// // "Hel"
776+
/// // "lo,"
777+
/// // " wo"
778+
/// // "rl"
779+
/// // "d!"
780+
///
781+
/// - Complexity: O(1) if the collection conforms to `RandomAccessCollection`,
782+
/// otherwise O(*n*), where *n* is the length of the collection.
768783
@inlinable
769784
public func evenlyChunked(into count: Int) -> EvenChunks<Self> {
770785
precondition(count >= 0, "Can't divide into a negative number of chunks")

0 commit comments

Comments
 (0)