|
| 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 | + |
| 51 | + |
| 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 | + |
0 commit comments