Combinations.swift 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. //===----------------------------------------------------------------------===//
  2. //
  3. // This source file is part of the Swift Algorithms open source project
  4. //
  5. // Copyright (c) 2020-2021 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. /// A collection wrapper that generates combinations of a base collection.
  12. public struct CombinationsSequence<Base: Collection> {
  13. /// The collection to iterate over for combinations.
  14. @usableFromInline
  15. internal let base: Base
  16. @usableFromInline
  17. internal let baseCount: Int
  18. /// The range of accepted sizes of combinations.
  19. ///
  20. /// - Note: This may be `nil` if the attempted range entirely exceeds the
  21. /// upper bounds of the size of the `base` collection.
  22. @usableFromInline
  23. internal let kRange: Range<Int>?
  24. /// Initializes a `CombinationsSequence` for all combinations of `base` of
  25. /// size `k`.
  26. ///
  27. /// - Parameters:
  28. /// - base: The collection to iterate over for combinations.
  29. /// - k: The expected size of each combination.
  30. @inlinable
  31. internal init(_ base: Base, k: Int) {
  32. self.init(base, kRange: k...k)
  33. }
  34. /// Initializes a `CombinationsSequence` for all combinations of `base` of
  35. /// sizes within a given range.
  36. ///
  37. /// - Parameters:
  38. /// - base: The collection to iterate over for combinations.
  39. /// - kRange: The range of accepted sizes of combinations.
  40. @inlinable
  41. internal init<R: RangeExpression>(
  42. _ base: Base, kRange: R
  43. ) where R.Bound == Int {
  44. let range = kRange.relative(to: 0 ..< .max)
  45. self.base = base
  46. let baseCount = base.count
  47. self.baseCount = baseCount
  48. let upperBound = baseCount + 1
  49. self.kRange = range.lowerBound < upperBound
  50. ? range.clamped(to: 0 ..< upperBound)
  51. : nil
  52. }
  53. /// The total number of combinations.
  54. @inlinable
  55. public var count: Int {
  56. guard let k = self.kRange else { return 0 }
  57. let n = baseCount
  58. if k == 0 ..< (n + 1) {
  59. return 1 << n
  60. }
  61. func binomial(n: Int, k: Int) -> Int {
  62. switch k {
  63. case n, 0: return 1
  64. case n...: return 0
  65. case (n / 2 + 1)...: return binomial(n: n, k: n - k)
  66. default: return n * binomial(n: n - 1, k: k - 1) / k
  67. }
  68. }
  69. return k.map {
  70. binomial(n: n, k: $0)
  71. }.reduce(0, +)
  72. }
  73. }
  74. extension CombinationsSequence: Sequence {
  75. /// The iterator for a `CombinationsSequence` instance.
  76. public struct Iterator: IteratorProtocol {
  77. @usableFromInline
  78. internal let base: Base
  79. /// The current range of accepted sizes of combinations.
  80. ///
  81. /// - Note: The range is contracted until empty while iterating over
  82. /// combinations of different sizes. When the range is empty, iteration is
  83. /// finished.
  84. @usableFromInline
  85. internal var kRange: Range<Int>
  86. /// Whether or not iteration is finished (`kRange` is empty)
  87. @inlinable
  88. internal var isFinished: Bool {
  89. return kRange.isEmpty
  90. }
  91. @usableFromInline
  92. internal var indexes: [Base.Index]
  93. @inlinable
  94. internal init(_ combinations: CombinationsSequence) {
  95. self.base = combinations.base
  96. self.kRange = combinations.kRange ?? 0..<0
  97. self.indexes = Array(combinations.base.indices.prefix(kRange.lowerBound))
  98. }
  99. /// Advances the current indices to the next set of combinations. If
  100. /// `indexes.count == 3` and `base.count == 5`, the indices advance like
  101. /// this:
  102. ///
  103. /// [0, 1, 2]
  104. /// [0, 1, 3]
  105. /// [0, 1, 4] *
  106. /// // * `base.endIndex` reached in `indexes.last`
  107. /// // Advance penultimate index and propagate that change
  108. /// [0, 2, 3]
  109. /// [0, 2, 4] *
  110. /// [0, 3, 4] *
  111. /// [1, 2, 3]
  112. /// [1, 2, 4] *
  113. /// [1, 3, 4] *
  114. /// [2, 3, 4] *
  115. /// // Can't advance without needing to go past `base.endIndex`,
  116. /// // so the iteration is finished.
  117. @inlinable
  118. internal mutating func advance() {
  119. /// Advances `kRange` by incrementing its `lowerBound` until the range is
  120. /// empty, when iteration is finished.
  121. func advanceKRange() {
  122. if kRange.lowerBound < kRange.upperBound {
  123. let advancedLowerBound = kRange.lowerBound + 1
  124. kRange = advancedLowerBound ..< kRange.upperBound
  125. indexes.removeAll(keepingCapacity: true)
  126. indexes.append(contentsOf: base.indices.prefix(kRange.lowerBound))
  127. }
  128. }
  129. guard !indexes.isEmpty else {
  130. // Initial state for combinations of 0 elements is an empty array with
  131. // `finished == false`. Even though no indexes are involved, advancing
  132. // from that state means we are finished with iterating.
  133. advanceKRange()
  134. return
  135. }
  136. let i = indexes.count - 1
  137. base.formIndex(after: &indexes[i])
  138. if indexes[i] != base.endIndex { return }
  139. var j = i
  140. while indexes[i] == base.endIndex {
  141. j -= 1
  142. guard j >= 0 else {
  143. // Finished iterating over combinations of this size.
  144. advanceKRange()
  145. return
  146. }
  147. base.formIndex(after: &indexes[j])
  148. for k in indexes.indices[(j + 1)...] {
  149. indexes[k] = base.index(after: indexes[k - 1])
  150. if indexes[k] == base.endIndex {
  151. break
  152. }
  153. }
  154. }
  155. }
  156. @inlinable
  157. public mutating func next() -> [Base.Element]? {
  158. guard !isFinished else { return nil }
  159. defer { advance() }
  160. return indexes.map { i in base[i] }
  161. }
  162. }
  163. @inlinable
  164. public func makeIterator() -> Iterator {
  165. Iterator(self)
  166. }
  167. }
  168. extension CombinationsSequence: LazySequenceProtocol
  169. where Base: LazySequenceProtocol {}
  170. //===----------------------------------------------------------------------===//
  171. // combinations(ofCount:)
  172. //===----------------------------------------------------------------------===//
  173. extension Collection {
  174. /// Returns a collection of combinations of this collection's elements, with
  175. /// each combination having the specified number of elements.
  176. ///
  177. /// This example prints the different combinations of 1 and 2 from an array of
  178. /// four colors:
  179. ///
  180. /// let colors = ["fuchsia", "cyan", "mauve", "magenta"]
  181. /// for combo in colors.combinations(ofCount: 1...2) {
  182. /// print(combo.joined(separator: ", "))
  183. /// }
  184. /// // fuchsia
  185. /// // cyan
  186. /// // mauve
  187. /// // magenta
  188. /// // fuchsia, cyan
  189. /// // fuchsia, mauve
  190. /// // fuchsia, magenta
  191. /// // cyan, mauve
  192. /// // cyan, magenta
  193. /// // mauve, magenta
  194. ///
  195. /// The returned collection presents combinations in a consistent order, where
  196. /// the indices in each combination are in ascending lexicographical order.
  197. /// That is, in the example above, the combinations in order are the elements
  198. /// at `[0]`, `[1]`, `[2]`, `[3]`, `[0, 1]`, `[0, 2]`, `[0, 3]`, `[1, 2]`,
  199. /// `[1, 3]`, and finally `[2, 3]`.
  200. ///
  201. /// This example prints _all_ the combinations (including an empty array and
  202. /// the original collection) from an array of numbers:
  203. ///
  204. /// let numbers = [10, 20, 30, 40]
  205. /// for combo in numbers.combinations(ofCount: 0...) {
  206. /// print(combo)
  207. /// }
  208. /// // []
  209. /// // [10]
  210. /// // [20]
  211. /// // [30]
  212. /// // [40]
  213. /// // [10, 20]
  214. /// // [10, 30]
  215. /// // [10, 40]
  216. /// // [20, 30]
  217. /// // [20, 40]
  218. /// // [30, 40]
  219. /// // [10, 20, 30]
  220. /// // [10, 20, 40]
  221. /// // [10, 30, 40]
  222. /// // [20, 30, 40]
  223. /// // [10, 20, 30, 40]
  224. ///
  225. /// If `kRange` is `0...0`, the resulting sequence has exactly one element, an
  226. /// empty array. The given range is limited to `0...base.count`. If the
  227. /// limited range is empty, the resulting sequence has no elements.
  228. ///
  229. /// - Parameter kRange: The range of numbers of elements to include in each
  230. /// combination.
  231. ///
  232. /// - Complexity: O(1) for random-access base collections. O(*n*) where *n*
  233. /// is the number of elements in the base collection, since
  234. /// `CombinationsSequence` accesses the `count` of the base collection.
  235. @inlinable
  236. public func combinations<R: RangeExpression>(
  237. ofCount kRange: R
  238. ) -> CombinationsSequence<Self> where R.Bound == Int {
  239. CombinationsSequence(self, kRange: kRange)
  240. }
  241. /// Returns a collection of combinations of this collection's elements, with
  242. /// each combination having the specified number of elements.
  243. ///
  244. /// This example prints the different combinations of three from an array of
  245. /// four colors:
  246. ///
  247. /// let colors = ["fuchsia", "cyan", "mauve", "magenta"]
  248. /// for combo in colors.combinations(ofCount: 3) {
  249. /// print(combo.joined(separator: ", "))
  250. /// }
  251. /// // fuchsia, cyan, mauve
  252. /// // fuchsia, cyan, magenta
  253. /// // fuchsia, mauve, magenta
  254. /// // cyan, mauve, magenta
  255. ///
  256. /// The returned collection presents combinations in a consistent order, where
  257. /// the indices in each combination are in ascending lexicographical order.
  258. /// That is, in the example above, the combinations in order are the elements
  259. /// at `[0, 1, 2]`, `[0, 1, 3]`, `[0, 2, 3]`, and finally `[1, 2, 3]`.
  260. ///
  261. /// If `k` is zero, the resulting sequence has exactly one element, an empty
  262. /// array. If `k` is greater than the number of elements in this sequence,
  263. /// the resulting sequence has no elements.
  264. ///
  265. /// - Parameter k: The number of elements to include in each combination.
  266. ///
  267. /// - Complexity: O(1) for random-access base collections. O(*n*) where *n*
  268. /// is the number of elements in the base collection, since
  269. /// `CombinationsSequence` accesses the `count` of the base collection.
  270. @inlinable
  271. public func combinations(ofCount k: Int) -> CombinationsSequence<Self> {
  272. precondition(k >= 0, "Can't have combinations with a negative number of elements.")
  273. return CombinationsSequence(self, k: k)
  274. }
  275. }