Skip to content

Commit 888985a

Browse files
committed
Add methods scanning already-sorted sequences
Add a method for already-sorted sequences that returns each unique value, paired with the count of each value. Add another method that returns each unique value. Have both eager and lazy variants for each method.
1 parent 0e939e7 commit 888985a

File tree

6 files changed

+458
-0
lines changed

6 files changed

+458
-0
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ This project follows semantic versioning.
1212

1313
- Bidirectional collections have a new `ends(with:)` method that matches
1414
the behavior of the standard library's `starts(with:)` method. ([#224])
15+
- Sequences that are already sorted can use the `countSortedDuplicates` and
16+
`withoutSortedDuplicates` methods, with eager and lazy versions.
17+
The former returns each unique value paired with the count of
18+
that value's occurances.
19+
The latter returns each unique value,
20+
turning a possibly non-decreasing sequence to a strictly-increasing one.
1521

1622
<!-- *No new changes.* -->
1723

Guides/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ These guides describe the design and intention behind the APIs included in the `
3232
- [`suffix(while:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Suffix.md): Returns the suffix of a collection where all element pass a given predicate.
3333
- [`trimmingPrefix(while:)`, `trimmingSuffix(while)`, `trimming(while:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Trim.md): Returns a slice by trimming elements from a collection's start, end, or both. The mutating `trim...` methods trim a collection in place.
3434
- [`uniqued()`, `uniqued(on:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Unique.md): The unique elements of a collection, preserving their order.
35+
- [`withoutSortedDuplicates()`, `withoutSortedDuplicates(by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/SortedDuplicates.md): Given an already-sorted sequence and the sorting predicate, reduce all runs of a unique value to a single element each. Has eager and lazy variants.
3536
- [`minAndMax()`, `minAndMax(by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/MinMax.md): Returns the smallest and largest elements of a sequence.
3637

3738
#### Partial sorting
@@ -42,6 +43,7 @@ These guides describe the design and intention behind the APIs included in the `
4243

4344
- [`adjacentPairs()`](https://github.com/apple/swift-algorithms/blob/main/Guides/AdjacentPairs.md): Lazily iterates over tuples of adjacent elements.
4445
- [`chunked(by:)`, `chunked(on:)`, `chunks(ofCount:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Chunked.md): Eager and lazy operations that break a collection into chunks based on either a binary predicate or when the result of a projection changes or chunks of a given count.
46+
- [`countSortedDuplicates()`, `countSortedDuplicates(by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/SortedDuplicates.md): Given an already-sorted sequence and the sorting predicate, return each unique value, pairing each with the number of occurances. Has eager and lazy variants.
4547
- [`firstNonNil(_:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/FirstNonNil.md): Returns the first non-`nil` result from transforming a sequence's elements.
4648
- [`grouped(by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/Grouped.md): Group up elements using the given closure, returning a Dictionary of those groups, keyed by the results of the closure.
4749
- [`indexed()`](https://github.com/apple/swift-algorithms/blob/main/Guides/Indexed.md): Iterate over tuples of a collection's indices and elements.

Guides/SortedDuplicates.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Sorted Duplicates
2+
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/SortedDuplicates.swift) |
3+
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/SortedDuplicatesTests.swift)]
4+
5+
Being a given a sequence that is already sorted, recognize each run of
6+
identical values.
7+
Use that to determine the length of each identical-value run of
8+
identical values.
9+
Or filter out the duplicate values by removing all occurances of
10+
a given value besides the first.
11+
12+
```swift
13+
// Put examples here
14+
```
15+
16+
## Detailed Design
17+
18+
```swift
19+
extension Sequence {
20+
public func countSortedDuplicates(
21+
by areInIncreasingOrder: (Element, Element) throws -> Bool
22+
) rethrows -> [(value: Element, count: Int)]
23+
24+
public func withoutSortedDuplicates(
25+
by areInIncreasingOrder: (Element, Element) throws -> Bool
26+
) rethrows -> [Element]
27+
}
28+
29+
extension Sequence where Self.Element : Comparable {
30+
public func countSortedDuplicates() -> [(value: Element, count: Int)]
31+
32+
public func withoutSortedDuplicates() -> [Element]
33+
}
34+
35+
extension LazySequenceProtocol {
36+
public func countSortedDuplicates(
37+
by areInIncreasingOrder: @escaping (Element, Element) -> Bool
38+
) -> LazyCountDuplicatesSequence<Elements>
39+
40+
public func withoutSortedDuplicates(
41+
by areInIncreasingOrder: @escaping (Element, Element) -> Bool
42+
) -> some (Sequence<Element> & LazySequenceProtocol)
43+
}
44+
45+
extension LazySequenceProtocol where Self.Element : Comparable {
46+
public func countSortedDuplicates()
47+
-> LazyCountDuplicatesSequence<Elements>
48+
49+
public func withoutSortedDuplicates()
50+
-> some (Sequence<Element> & LazySequenceProtocol)
51+
}
52+
53+
public struct LazyCountDuplicatesSequence<Base: Sequence>
54+
: LazySequenceProtocol
55+
{ /*...*/ }
56+
57+
public struct CountDuplicatesIterator<Base: IteratorProtocol>
58+
: IteratorProtocol
59+
{ /*...*/ }
60+
```
61+
62+
### Complexity
63+
64+
Calling the lazy methods, those defined on `LazySequenceProtocol`, is O(_1_).
65+
Calling the eager methods, those returning an array, is O(_n_).

Sources/Algorithms/Documentation.docc/Selecting.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,24 @@ or iterate of elements with their indices.
1818

1919
- ``Swift/Collection/indexed()``
2020

21+
### Counting each Element in a Sorted Sequence
22+
23+
- ``Swift/Sequence/countSortedDuplicates(by:)``
24+
- ``Swift/Sequence/countSortedDuplicates()``
25+
- ``Swift/LazySequenceProtocol/countSortedDuplicates(by:)``
26+
- ``Swift/LazySequenceProtocol/countSortedDuplicates()``
27+
28+
### Removing Duplicates from a Sorted Sequence
29+
30+
- ``Swift/Sequence/withoutSortedDuplicates(by:)``
31+
- ``Swift/Sequence/withoutSortedDuplicates()``
32+
- ``Swift/LazySequenceProtocol/withoutSortedDuplicates(by:)``
33+
- ``Swift/LazySequenceProtocol/withoutSortedDuplicates()``
34+
2135
### Supporting Types
2236

2337
- ``IndexedCollection``
2438
- ``StridingSequence``
2539
- ``StridingCollection``
40+
- ``LazyCountDuplicatesSequence``
41+
- ``CountDuplicatesIterator``

0 commit comments

Comments
 (0)