Skip to content

Commit bd64bef

Browse files
authoredFeb 26, 2021
Rename sortedPrefix methods (#77)
This renames sortedPrefix to min(count:), adds max(count:), and moves both methods down to Sequence. In order to still provide the optimization when `count` is close to a collection's length, we include a Collection-specific overload of all methods. These won't be accessed when in a Sequence-generic context, but it's the best we can do without adding these methods as protocol requirements.
1 parent 32837b9 commit bd64bef

File tree

7 files changed

+631
-449
lines changed

7 files changed

+631
-449
lines changed
 

‎Guides/MinMax.md

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
# Min/Max with Count
2+
3+
[[Source](https://github.com/apple/swift-algorithms/blob/main/Sources/Algorithms/MinMax.swift) |
4+
[Tests](https://github.com/apple/swift-algorithms/blob/main/Tests/SwiftAlgorithmsTests/MinMaxTests.swift)]
5+
6+
Returns the smallest or largest elements of this collection, sorted by a predicate or in the order defined by `Comparable` conformance.
7+
8+
If you need to sort a collection but only need access to a prefix or suffix of the sorted elements, using these methods can give you a performance boost over sorting the entire collection. The order of equal elements is guaranteed to be preserved.
9+
10+
```swift
11+
let numbers = [7, 1, 6, 2, 8, 3, 9]
12+
let smallestThree = numbers.min(count: 3, sortedBy: <)
13+
// [1, 2, 3]
14+
```
15+
16+
## Detailed Design
17+
18+
This adds the `Collection` methods shown below:
19+
20+
```swift
21+
extension Collection {
22+
public func min(
23+
count: Int,
24+
sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
25+
) rethrows -> [Element]
26+
27+
public func max(
28+
count: Int,
29+
sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
30+
) rethrows -> [Element]
31+
}
32+
```
33+
34+
Additionally, versions of these methods for `Comparable` types are also provided:
35+
36+
```swift
37+
extension Collection where Element: Comparable {
38+
public func min(count: Int) -> [Element]
39+
40+
public func max(count: Int) -> [Element]
41+
}
42+
```
43+
44+
### Complexity
45+
46+
The algorithm used is based on [Soroush Khanlou's research on this matter](https://khanlou.com/2018/12/analyzing-complexity/). The total complexity is `O(k log k + nk)`, which will result in a runtime close to `O(n)` if *k* is a small amount. If *k* is a large amount (more than 10% of the collection), we fall back to sorting the entire array. Realistically, this means the worst case is actually `O(n log n)`.
47+
48+
Here are some benchmarks we made that demonstrates how this implementation (SmallestM) behaves when *k* increases (before implementing the fallback):
49+
50+
![Benchmark](Resources/SortedPrefix/FewElements.png)
51+
![Benchmark 2](Resources/SortedPrefix/ManyElements.png)
52+
53+
### Comparison with other languages
54+
55+
**C++:** The `<algorithm>` library defines a `partial_sort` function where the entire array is returned using a partial heap sort.
56+
57+
**Python:** Defines a `heapq` priority queue that can be used to manually achieve the same result.
58+

‎Guides/SortedPrefix.md

-48
This file was deleted.

‎README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Read more about the package, and the intent behind it, in the [announcement on s
3131

3232
#### Partial sorting
3333

34-
- [`sortedPrefix(_:by:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/SortedPrefix.md): Returns the first k elements of a sorted collection.
34+
- [`min(count:)`, `max(count:)`, `min(count:sortedBy:)`, `max(count:sortedBy:)`](https://github.com/apple/swift-algorithms/blob/main/Guides/MinMax.md): Returns the smallest or largest elements of a collection, sorted by a predicate.
3535

3636
#### Other useful operations
3737

0 commit comments

Comments
 (0)