MinMax.swift 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2020 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See https://swift.org/LICENSE.txt for license information
  9. //
  10. //===----------------------------------------------------------------------===//
  11. extension Sequence {
  12. /// Implementation for min(count:areInIncreasingOrder:)
  13. @inlinable
  14. internal func _minImplementation(
  15. count: Int,
  16. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  17. ) rethrows -> [Element] {
  18. var iterator = makeIterator()
  19. var result: [Element] = []
  20. result.reserveCapacity(count)
  21. while result.count < count, let e = iterator.next() {
  22. result.append(e)
  23. }
  24. try result.sort(by: areInIncreasingOrder)
  25. while let e = iterator.next() {
  26. // To be part of `result`, `e` must be strictly less than `result.last`.
  27. guard try areInIncreasingOrder(e, result.last!) else { continue }
  28. let insertionIndex =
  29. try result.partitioningIndex { try areInIncreasingOrder(e, $0) }
  30. assert(insertionIndex != result.endIndex)
  31. result.removeLast()
  32. result.insert(e, at: insertionIndex)
  33. }
  34. return result
  35. }
  36. /// Implementation for max(count:areInIncreasingOrder:)
  37. @inlinable
  38. internal func _maxImplementation(
  39. count: Int,
  40. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  41. ) rethrows -> [Element] {
  42. var iterator = makeIterator()
  43. var result: [Element] = []
  44. result.reserveCapacity(count)
  45. while result.count < count, let e = iterator.next() {
  46. result.append(e)
  47. }
  48. try result.sort(by: areInIncreasingOrder)
  49. while let e = iterator.next() {
  50. // To be part of `result`, `e` must be greater/equal to `result.first`.
  51. guard try !areInIncreasingOrder(e, result.first!) else { continue }
  52. let insertionIndex =
  53. try result.partitioningIndex { try areInIncreasingOrder(e, $0) }
  54. assert(insertionIndex > 0)
  55. // Inserting `e` and then removing the first element (or vice versa)
  56. // would perform a double shift, so we manually shift down the elements
  57. // before dropping `e` in.
  58. var i = 1
  59. while i < insertionIndex {
  60. result[i - 1] = result[i]
  61. i += 1
  62. }
  63. result[insertionIndex - 1] = e
  64. }
  65. return result
  66. }
  67. /// Returns the smallest elements of this sequence, as sorted by the given
  68. /// predicate.
  69. ///
  70. /// This example partially sorts an array of integers to retrieve its three
  71. /// smallest values:
  72. ///
  73. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  74. /// let smallestThree = numbers.min(count: 3, sortedBy: <)
  75. /// // [1, 2, 3]
  76. ///
  77. /// If you need to sort a sequence but only need to access its smallest
  78. /// elements, using this method can give you a performance boost over sorting
  79. /// the entire sequence. The order of equal elements is guaranteed to be
  80. /// preserved.
  81. ///
  82. /// - Parameters:
  83. /// - count: The number of elements to return. If `count` is greater than
  84. /// the number of elements in this sequence, all of the sequence's
  85. /// elements are returned.
  86. /// - areInIncreasingOrder: A predicate that returns `true` if its
  87. /// first argument should be ordered before its second argument;
  88. /// otherwise, `false`.
  89. /// - Returns: An array of the smallest `count` elements of this sequence,
  90. /// sorted according to `areInIncreasingOrder`.
  91. ///
  92. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  93. /// sequence and *k* is `count`.
  94. @inlinable
  95. public func min(
  96. count: Int,
  97. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  98. ) rethrows -> [Element] {
  99. precondition(count >= 0, """
  100. Cannot find a minimum with a negative count of elements!
  101. """
  102. )
  103. // Do nothing if we're prefixing nothing.
  104. guard count > 0 else {
  105. return []
  106. }
  107. return try _minImplementation(count: count, sortedBy: areInIncreasingOrder)
  108. }
  109. /// Returns the largest elements of this sequence, as sorted by the given
  110. /// predicate.
  111. ///
  112. /// This example partially sorts an array of integers to retrieve its three
  113. /// largest values:
  114. ///
  115. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  116. /// let smallestThree = numbers.max(count: 3, sortedBy: <)
  117. /// // [7, 8, 9]
  118. ///
  119. /// If you need to sort a sequence but only need to access its largest
  120. /// elements, using this method can give you a performance boost over sorting
  121. /// the entire sequence. The order of equal elements is guaranteed to be
  122. /// preserved.
  123. ///
  124. /// - Parameters:
  125. /// - count: The number of elements to return. If `count` is greater than
  126. /// the number of elements in this sequence, all of the sequence's
  127. /// elements are returned.
  128. /// - areInIncreasingOrder: A predicate that returns `true` if its
  129. /// first argument should be ordered before its second argument;
  130. /// otherwise, `false`.
  131. /// - Returns: An array of the largest `count` elements of this sequence,
  132. /// sorted according to `areInIncreasingOrder`.
  133. ///
  134. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  135. /// sequence and *k* is `count`.
  136. @inlinable
  137. public func max(
  138. count: Int,
  139. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  140. ) rethrows -> [Element] {
  141. precondition(count >= 0, """
  142. Cannot find a maximum with a negative count of elements!
  143. """
  144. )
  145. // Do nothing if we're suffixing nothing.
  146. guard count > 0 else {
  147. return []
  148. }
  149. return try _maxImplementation(count: count, sortedBy: areInIncreasingOrder)
  150. }
  151. }
  152. extension Sequence where Element: Comparable {
  153. /// Returns the smallest elements of this sequence.
  154. ///
  155. /// This example partially sorts an array of integers to retrieve its three
  156. /// smallest values:
  157. ///
  158. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  159. /// let smallestThree = numbers.min(count: 3)
  160. /// // [1, 2, 3]
  161. ///
  162. /// If you need to sort a sequence but only need to access its smallest
  163. /// elements, using this method can give you a performance boost over sorting
  164. /// the entire sequence. The order of equal elements is guaranteed to be
  165. /// preserved.
  166. ///
  167. /// - Parameter count: The number of elements to return. If `count` is greater
  168. /// than the number of elements in this sequence, all of the sequence's
  169. /// elements are returned.
  170. /// - Returns: An array of the smallest `count` elements of this sequence.
  171. ///
  172. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  173. /// sequence and *k* is `count`.
  174. @inlinable
  175. public func min(count: Int) -> [Element] {
  176. min(count: count, sortedBy: <)
  177. }
  178. /// Returns the largest elements of this sequence.
  179. ///
  180. /// This example partially sorts an array of integers to retrieve its three
  181. /// largest values:
  182. ///
  183. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  184. /// let smallestThree = numbers.max(count: 3)
  185. /// // [7, 8, 9]
  186. ///
  187. /// If you need to sort a sequence but only need to access its largest
  188. /// elements, using this method can give you a performance boost over sorting
  189. /// the entire sequence. The order of equal elements is guaranteed to be
  190. /// preserved.
  191. ///
  192. /// - Parameter count: The number of elements to return. If `count` is greater
  193. /// than the number of elements in this sequence, all of the sequence's
  194. /// elements are returned.
  195. /// - Returns: An array of the largest `count` elements of this sequence.
  196. ///
  197. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  198. /// sequence and *k* is `count`.
  199. @inlinable
  200. public func max(count: Int) -> [Element] {
  201. max(count: count, sortedBy: <)
  202. }
  203. }
  204. extension Collection {
  205. /// Returns the smallest elements of this collection, as sorted by the given
  206. /// predicate.
  207. ///
  208. /// This example partially sorts an array of integers to retrieve its three
  209. /// smallest values:
  210. ///
  211. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  212. /// let smallestThree = numbers.min(count: 3, sortedBy: <)
  213. /// // [1, 2, 3]
  214. ///
  215. /// If you need to sort a collection but only need to access its smallest
  216. /// elements, using this method can give you a performance boost over sorting
  217. /// the entire collection. The order of equal elements is guaranteed to be
  218. /// preserved.
  219. ///
  220. /// - Parameters:
  221. /// - count: The number of elements to return. If `count` is greater than
  222. /// the number of elements in this collection, all of the collection's
  223. /// elements are returned.
  224. /// - areInIncreasingOrder: A predicate that returns `true` if its
  225. /// first argument should be ordered before its second argument;
  226. /// otherwise, `false`.
  227. /// - Returns: An array of the smallest `count` elements of this collection,
  228. /// sorted according to `areInIncreasingOrder`.
  229. ///
  230. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  231. /// collection and *k* is `count`.
  232. @inlinable
  233. public func min(
  234. count: Int,
  235. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  236. ) rethrows -> [Element] {
  237. precondition(count >= 0, """
  238. Cannot find a minimum with a negative count of elements!
  239. """
  240. )
  241. // Do nothing if we're prefixing nothing.
  242. guard count > 0 else {
  243. return []
  244. }
  245. // Make sure we are within bounds.
  246. let prefixCount = Swift.min(count, self.count)
  247. // If we're attempting to prefix more than 10% of the collection, it's
  248. // faster to sort everything.
  249. guard prefixCount < (self.count / 10) else {
  250. return Array(try sorted(by: areInIncreasingOrder).prefix(prefixCount))
  251. }
  252. return try _minImplementation(count: count, sortedBy: areInIncreasingOrder)
  253. }
  254. /// Returns the largest elements of this collection, as sorted by the given
  255. /// predicate.
  256. ///
  257. /// This example partially sorts an array of integers to retrieve its three
  258. /// largest values:
  259. ///
  260. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  261. /// let smallestThree = numbers.max(count: 3, sortedBy: <)
  262. /// // [7, 8, 9]
  263. ///
  264. /// If you need to sort a collection but only need to access its largest
  265. /// elements, using this method can give you a performance boost over sorting
  266. /// the entire collection. The order of equal elements is guaranteed to be
  267. /// preserved.
  268. ///
  269. /// - Parameters:
  270. /// - count: The number of elements to return. If `count` is greater than
  271. /// the number of elements in this collection, all of the collection's
  272. /// elements are returned.
  273. /// - areInIncreasingOrder: A predicate that returns `true` if its
  274. /// first argument should be ordered before its second argument;
  275. /// otherwise, `false`.
  276. /// - Returns: An array of the largest `count` elements of this collection,
  277. /// sorted according to `areInIncreasingOrder`.
  278. ///
  279. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  280. /// collection and *k* is `count`.
  281. @inlinable
  282. public func max(
  283. count: Int,
  284. sortedBy areInIncreasingOrder: (Element, Element) throws -> Bool
  285. ) rethrows -> [Element] {
  286. precondition(count >= 0, """
  287. Cannot find a maximum with a negative count of elements!
  288. """
  289. )
  290. // Do nothing if we're suffixing nothing.
  291. guard count > 0 else {
  292. return []
  293. }
  294. // Make sure we are within bounds.
  295. let suffixCount = Swift.min(count, self.count)
  296. // If we're attempting to prefix more than 10% of the collection, it's
  297. // faster to sort everything.
  298. guard suffixCount < (self.count / 10) else {
  299. return Array(try sorted(by: areInIncreasingOrder).suffix(suffixCount))
  300. }
  301. return try _maxImplementation(count: count, sortedBy: areInIncreasingOrder)
  302. }
  303. }
  304. extension Collection where Element: Comparable {
  305. /// Returns the smallest elements of this collection.
  306. ///
  307. /// This example partially sorts an array of integers to retrieve its three
  308. /// smallest values:
  309. ///
  310. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  311. /// let smallestThree = numbers.min(count: 3)
  312. /// // [1, 2, 3]
  313. ///
  314. /// If you need to sort a collection but only need to access its smallest
  315. /// elements, using this method can give you a performance boost over sorting
  316. /// the entire collection. The order of equal elements is guaranteed to be
  317. /// preserved.
  318. ///
  319. /// - Parameter count: The number of elements to return. If `count` is greater
  320. /// than the number of elements in this collection, all of the collection's
  321. /// elements are returned.
  322. /// - Returns: An array of the smallest `count` elements of this collection.
  323. ///
  324. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  325. /// collection and *k* is `count`.
  326. @inlinable
  327. public func min(count: Int) -> [Element] {
  328. min(count: count, sortedBy: <)
  329. }
  330. /// Returns the largest elements of this collection.
  331. ///
  332. /// This example partially sorts an array of integers to retrieve its three
  333. /// largest values:
  334. ///
  335. /// let numbers = [7, 1, 6, 2, 8, 3, 9]
  336. /// let smallestThree = numbers.max(count: 3)
  337. /// // [7, 8, 9]
  338. ///
  339. /// If you need to sort a collection but only need to access its largest
  340. /// elements, using this method can give you a performance boost over sorting
  341. /// the entire collection. The order of equal elements is guaranteed to be
  342. /// preserved.
  343. ///
  344. /// - Parameter count: The number of elements to return. If `count` is greater
  345. /// than the number of elements in this collection, all of the collection's
  346. /// elements are returned.
  347. /// - Returns: An array of the largest `count` elements of this collection.
  348. ///
  349. /// - Complexity: O(*k* log *k* + *nk*), where *n* is the length of the
  350. /// collection and *k* is `count`.
  351. @inlinable
  352. public func max(count: Int) -> [Element] {
  353. max(count: count, sortedBy: <)
  354. }
  355. }
  356. //===----------------------------------------------------------------------===//
  357. // Simultaneous minimum and maximum evaluation
  358. //===----------------------------------------------------------------------===//
  359. extension Sequence {
  360. /// Returns both the minimum and maximum elements in the sequence, using the
  361. /// given predicate as the comparison between elements.
  362. ///
  363. /// The predicate must be a *strict weak ordering* over the elements. That is,
  364. /// for any elements `a`, `b`, and `c`, the following conditions must hold:
  365. ///
  366. /// - `areInIncreasingOrder(a, a)` is always `false`. (Irreflexivity)
  367. /// - If `areInIncreasingOrder(a, b)` and `areInIncreasingOrder(b, c)` are
  368. /// both `true`, then `areInIncreasingOrder(a, c)` is also
  369. /// `true`. (Transitive comparability)
  370. /// - Two elements are *incomparable* if neither is ordered before the other
  371. /// according to the predicate. If `a` and `b` are incomparable, and `b`
  372. /// and `c` are incomparable, then `a` and `c` are also incomparable.
  373. /// (Transitive incomparability)
  374. ///
  375. /// This example shows how to use the `minAndMax(by:)` method on a dictionary
  376. /// to find the key-value pair with the lowest value and the pair with the
  377. /// highest value.
  378. ///
  379. /// let hues = ["Heliotrope": 296, "Coral": 16, "Aquamarine": 156]
  380. /// if let extremeHues = hues.minAndMax(by: {$0.value < $1.value}) {
  381. /// print(extremeHues.min, extremeHues.max)
  382. /// } else {
  383. /// print("There are no hues")
  384. /// }
  385. /// // Prints: "(key: "Coral", value: 16) (key: "Heliotrope", value: 296)"
  386. ///
  387. /// - Precondition: The sequence is finite.
  388. ///
  389. /// - Parameter areInIncreasingOrder: A predicate that returns `true` if its
  390. /// first argument should be ordered before its second argument; otherwise,
  391. /// `false`.
  392. /// - Returns: A tuple with the sequence's minimum element, followed by its
  393. /// maximum element. If the sequence provides multiple qualifying minimum
  394. /// elements, the first equivalent element is returned; of multiple maximum
  395. /// elements, the last is returned. If the sequence has no elements, the
  396. /// method returns `nil`.
  397. ///
  398. /// - Complexity: O(*n*), where *n* is the length of the sequence.
  399. @inlinable
  400. public func minAndMax(
  401. by areInIncreasingOrder: (Element, Element) throws -> Bool
  402. ) rethrows -> (min: Element, max: Element)? {
  403. // Check short sequences.
  404. var iterator = makeIterator()
  405. guard var lowest = iterator.next() else { return nil }
  406. guard var highest = iterator.next() else { return (lowest, lowest) }
  407. // Confirm the initial bounds.
  408. if try areInIncreasingOrder(highest, lowest) { swap(&lowest, &highest) }
  409. // Read the elements in pairwise. Structuring the comparisons around this
  410. // is actually faster than loops based on extracting and testing elements
  411. // one-at-a-time.
  412. while var low = iterator.next() {
  413. var high = iterator.next() ?? low
  414. if try areInIncreasingOrder(high, low) { swap(&low, &high) }
  415. if try areInIncreasingOrder(low, lowest) { lowest = low }
  416. if try !areInIncreasingOrder(high, highest) { highest = high }
  417. }
  418. return (lowest, highest)
  419. }
  420. }
  421. extension Sequence where Element: Comparable {
  422. /// Returns both the minimum and maximum elements in the sequence.
  423. ///
  424. /// This example finds the smallest and largest values in an array of height
  425. /// measurements.
  426. ///
  427. /// let heights = [67.5, 65.7, 64.3, 61.1, 58.5, 60.3, 64.9]
  428. /// if let (lowestHeight, greatestHeight) = heights.minAndMax() {
  429. /// print(lowestHeight, greatestHeight)
  430. /// } else {
  431. /// print("The list of heights is empty")
  432. /// }
  433. /// // Prints: "58.5 67.5"
  434. ///
  435. /// - Precondition: The sequence is finite.
  436. ///
  437. /// - Returns: A tuple with the sequence's minimum element, followed by its
  438. /// maximum element. If the sequence provides multiple qualifying minimum
  439. /// elements, the first equivalent element is returned; of multiple maximum
  440. /// elements, the last is returned. If the sequence has no elements, the
  441. /// method returns `nil`.
  442. ///
  443. /// - Complexity: O(*n*), where *n* is the length of the sequence.
  444. @inlinable
  445. public func minAndMax() -> (min: Element, max: Element)? {
  446. minAndMax(by: <)
  447. }
  448. }