diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 00000000..c75c9abe --- /dev/null +++ b/.spi.yml @@ -0,0 +1,5 @@ +version: 1 +builder: + configs: + - documentation_targets: [Algorithms] + diff --git a/Sources/Algorithms/Chunked.swift b/Sources/Algorithms/Chunked.swift index 52efbd0b..74f774ba 100644 --- a/Sources/Algorithms/Chunked.swift +++ b/Sources/Algorithms/Chunked.swift @@ -777,8 +777,8 @@ extension ChunksOfCountCollection { } extension Collection { - /// Returns a collection of subsequences of this collection, each with the - /// specified length. + /// Returns a collection of subsequences, each with up to the specified + /// length. /// /// If the number of elements in the collection is evenly divided by `count`, /// then every chunk will have a length equal to `count`. Otherwise, every @@ -792,8 +792,7 @@ extension Collection { /// // [1, 2, 3, 4, 5] /// // [6, 7, 8, 9, 10] /// - /// print(c.chunks(ofCount: 3).map(Array.init)) - /// for chunk in numbers.chunks(ofCount: 5) { + /// for chunk in numbers.chunks(ofCount: 3) { /// print(chunk) /// } /// // [1, 2, 3] @@ -808,6 +807,7 @@ extension Collection { /// /// - Complexity: O(1) if the collection conforms to `RandomAccessCollection`; /// otherwise, O(*k*), where *k* is equal to `count`. + /// @inlinable public func chunks(ofCount count: Int) -> ChunksOfCountCollection { precondition(count > 0, "Cannot chunk with count <= 0!") @@ -828,7 +828,8 @@ extension ChunksOfCountCollection: LazyCollectionProtocol //===----------------------------------------------------------------------===// extension Collection { - /// Returns a collection of evenly divided subsequences of this collection. + /// Returns a collection of evenly divided consecutive subsequences of this + /// collection. /// /// This method divides the collection into a given number of evenly sized /// chunks. If the length of the collection is not divisible by `count`, the diff --git a/Sources/Algorithms/Documentation.docc/Algorithms.md b/Sources/Algorithms/Documentation.docc/Algorithms.md index 46269054..edd880af 100644 --- a/Sources/Algorithms/Documentation.docc/Algorithms.md +++ b/Sources/Algorithms/Documentation.docc/Algorithms.md @@ -5,8 +5,25 @@ along with their related types. ## Overview -This library adds a variety of extended operations to the Swift standard library's -`Sequence` and `Collection` protocols, via extension methods and global functions. +The Algorithms package provides a variety of sequence and collection operations, letting you cycle over a collection's elements, find combinations and permutations, create a random sample, and more. + +For example, the package includes a group of "chunking" methods, each of which breaks a collection into consecutive subsequences. One version tests adjacent elements to find the breaking point between chunks — you can use it to quickly separate an array into ascending runs: + +```swift +let numbers = [10, 20, 30, 10, 40, 40, 10, 20] +let chunks = numbers.chunked(by: { $0 <= $1 }) +// [[10, 20, 30], [10, 40, 40], [10, 20]] +``` + +Another version looks for a change in the transformation of each successive value. You can use that to separate a list of names into groups by the first character: + +```swift +let names = ["Cassie", "Chloe", "Jasmine", "Jordan", "Taylor"] +let chunks = names.chunked(on: \.first) +// [["Cassie", "Chloe"], ["Jasmine", "Jordan"], ["Taylor"]] +``` + +Explore more chunking methods and the remainder of the Algorithms package, grouped in the following topics. ## Topics diff --git a/Sources/Algorithms/Documentation.docc/Chunking.md b/Sources/Algorithms/Documentation.docc/Chunking.md index 3c0699ab..c6f14485 100644 --- a/Sources/Algorithms/Documentation.docc/Chunking.md +++ b/Sources/Algorithms/Documentation.docc/Chunking.md @@ -4,6 +4,17 @@ Break collections into consecutive chunks by length, count, or based on closure- ## Overview +_Chunking_ is the process of breaking a collection into consecutive subsequences, without dropping or duplicating any of the collection's elements. After chunking a collection, joining the resulting subsequences produces the original collection of elements, unlike _splitting_, which consumes the separator element(s). + +```swift +let names = ["Ji-sun", "Jin-su", "Min-jae", "Young-ho"] +let evenlyChunked = names.chunks(ofCount: 2) +// ~ [["Ji-sun", "Jin-su"], ["Min-jae", "Young-ho"]] + +let chunkedByFirstLetter = names.chunked(on: \.first) +// equivalent to [("J", ["Ji-sun", "Jin-su"]), ("M", ["Min-jae"]), ("Y", ["Young-ho"])] +``` + ## Topics ### Chunking a Collection by Count @@ -13,10 +24,12 @@ Break collections into consecutive chunks by length, count, or based on closure- ### Chunking a Collection by Predicate -- ``Swift/Collection/chunked(on:)`` - ``Swift/Collection/chunked(by:)`` - ``Swift/LazySequenceProtocol/chunked(by:)`` -- ``Swift/LazySequenceProtocol/chunked(by:)`` + +### Chunking a Collection by Subject + +- ``Swift/Collection/chunked(on:)`` - ``Swift/LazySequenceProtocol/chunked(on:)`` ### Supporting Types diff --git a/Sources/Algorithms/Documentation.docc/DeprecatedScan.md b/Sources/Algorithms/Documentation.docc/DeprecatedScan.md index c1227306..38a82a9c 100644 --- a/Sources/Algorithms/Documentation.docc/DeprecatedScan.md +++ b/Sources/Algorithms/Documentation.docc/DeprecatedScan.md @@ -1,8 +1,8 @@ # DeprecatedScan -These methods are deprecated, use the `reductions` family of methods instead. +These methods are deprecated; use the `reductions` family of methods instead. -## Overview +See: ## Topics diff --git a/Sources/Algorithms/Documentation.docc/Extending.md b/Sources/Algorithms/Documentation.docc/Extending.md index 5d45a15f..f3d9bce7 100644 --- a/Sources/Algorithms/Documentation.docc/Extending.md +++ b/Sources/Algorithms/Documentation.docc/Extending.md @@ -3,6 +3,27 @@ Chain two collections end-to-end, or repeat a collection forever or a specific number of times. +## Overview + +_Chaining_ two collections + +```swift +let letters = chain("abcd", "EFGH") +// String(letters) == "abcdEFGH" + +for (num, letter) in zip((1...3).cycled(), letters) { + print(num, letter) +} +// 1 a +// 2 b +// 3 c +// 1 d +// 2 E +// 3 F +// 1 G +// 2 H +``` + ## Topics ### Chaining Two Collections diff --git a/Sources/Algorithms/Documentation.docc/Filtering.md b/Sources/Algorithms/Documentation.docc/Filtering.md index 46b72553..85073ab8 100644 --- a/Sources/Algorithms/Documentation.docc/Filtering.md +++ b/Sources/Algorithms/Documentation.docc/Filtering.md @@ -4,17 +4,32 @@ Remove duplicated elements or strip the `nil` values from a sequence or collecti ## Overview -Text +Use the _uniquing_ methods to remove duplicates from a sequence or collection, or to remove elements that have a duplicated property. + +```swift +let numbers = [1, 2, 3, 3, 2, 3, 3, 2, 2, 2, 1] + +let unique = numbers.uniqued() +// Array(unique) == [1, 2, 3] +``` + +The `compacted()` method removes all `nil` values from a sequence or collection of optionals: + +```swift +let array: [Int?] = [10, nil, 30, nil, 2, 3, nil, 5] +let withNoNils = array.compacted() +// Array(withNoNils) == [10, 30, 2, 3, 5] +``` ## Topics -### Uniqueing Elements +### Uniquing Elements - ``Swift/Sequence/uniqued()`` - ``Swift/Sequence/uniqued(on:)`` - ``Swift/LazySequenceProtocol/uniqued(on:)`` -### Filtering out nil Elements +### Filtering out `nil` Elements - ``Swift/Collection/compacted()`` - ``Swift/Sequence/compacted()`` diff --git a/Sources/Algorithms/Documentation.docc/Partitioning.md b/Sources/Algorithms/Documentation.docc/Partitioning.md index d1b1fdc0..091985dd 100644 --- a/Sources/Algorithms/Documentation.docc/Partitioning.md +++ b/Sources/Algorithms/Documentation.docc/Partitioning.md @@ -4,6 +4,35 @@ Partition a collection according to a unary predicate, rotate a collection around a particular index, or find the index where a collection is already partitioned. +## Overview + +A _stable partition_ maintains the relative order of elements within both partitions. + +```swift +// partition(by:) - unstable ordering +var numbers = [10, 20, 30, 40, 50, 60, 70, 80] +let p1 = numbers.partition(by: { $0.isMultiple(of: 20) }) +// p1 == 4 +// numbers == [10, 70, 30, 50, 40, 60, 20, 80] +// ^ start of second partition + +// stablePartition(by:) - maintains relative ordering +numbers = [10, 20, 30, 40, 50, 60, 70, 80] +let p2 = numbers.stablePartition(by: { $0.isMultiple(of: 20) }) +// p2 == 4 +// numbers == [10, 30, 50, 70, 20, 40, 60, 80] +// ^ start of second partition +``` + +Use the `rotate` method to shift the elements of a collection to start at a new position, moving the displaced elements to the end: + +```swift +var numbers = [10, 20, 30, 40, 50, 60, 70, 80] +let p = numbers.rotate(toStartAt: 2) +// numbers == [30, 40, 50, 60, 70, 80, 10, 20] +// p == 6 -- numbers[p] == 10 +``` + ## Topics ### Stable Partition diff --git a/Sources/Algorithms/Documentation.docc/Reductions.md b/Sources/Algorithms/Documentation.docc/Reductions.md index 81d7ea2b..50068218 100644 --- a/Sources/Algorithms/Documentation.docc/Reductions.md +++ b/Sources/Algorithms/Documentation.docc/Reductions.md @@ -2,6 +2,20 @@ Find the incremental values of a sequence "reduce" operation. +## Overview + +Call one of the `reductions` methods when you want the result of a `reduce` operation along with all of its intermediate values: + +```swift +let exclusiveRunningTotal = (1...5).reductions(0, +) +print(exclusiveRunningTotal) +// prints [0, 1, 3, 6, 10, 15] + +let inclusiveRunningTotal = (1...5).reductions(+) +print(inclusiveRunningTotal) +// prints [1, 3, 6, 10, 15] +``` + ## Topics - ``Swift/Sequence/reductions(_:)`` diff --git a/Sources/Algorithms/Documentation.docc/SlicingSplitting.md b/Sources/Algorithms/Documentation.docc/SlicingSplitting.md index 78db68ad..388422c1 100644 --- a/Sources/Algorithms/Documentation.docc/SlicingSplitting.md +++ b/Sources/Algorithms/Documentation.docc/SlicingSplitting.md @@ -15,8 +15,6 @@ Iterate over tuple pairs of adjacent elements, overlapping windows of a specifie ### Lazily Splitting a Collection -These methods… - - ``Swift/LazySequenceProtocol/split(separator:maxSplits:omittingEmptySubsequences:)-4q4x8`` - ``Swift/LazySequenceProtocol/split(maxSplits:omittingEmptySubsequences:whereSeparator:)-68oqf`` - ``Swift/LazySequenceProtocol/split(separator:maxSplits:omittingEmptySubsequences:)-a46s``