22//
33// This source file is part of the Swift Algorithms open source project
44//
5- // Copyright (c) 2020 Apple Inc. and the Swift project authors
5+ // Copyright (c) 2020-2021 Apple Inc. and the Swift project authors
66// Licensed under Apache License v2.0 with Runtime Library Exception
77//
88// See https://swift.org/LICENSE.txt for license information
@@ -15,16 +15,51 @@ public struct Combinations<Base: Collection> {
1515 public let base : Base
1616
1717 @usableFromInline
18- internal var k : Int
18+ internal let baseCount : Int
1919
20+ /// The range of accepted sizes of combinations.
21+ /// - Note: This may be `nil` if the attempted range entirely exceeds the
22+ /// upper bounds of the size of the `base` collection.
23+ @usableFromInline
24+ internal let kRange : Range < Int > ?
25+
26+ /// Initializes a `Combinations` for all combinations of `base` of size `k`.
27+ /// - Parameters:
28+ /// - base: The collection to iterate over for combinations.
29+ /// - k: The expected size of each combination.
2030 @usableFromInline
2131 internal init ( _ base: Base , k: Int ) {
32+ self . init ( base, kRange: k... k)
33+ }
34+
35+ /// Initializes a `Combinations` for all combinations of `base` of sizes
36+ /// within a given range.
37+ /// - Parameters:
38+ /// - base: The collection to iterate over for combinations.
39+ /// - kRange: The range of accepted sizes of combinations.
40+ @usableFromInline
41+ internal init < R: RangeExpression > (
42+ _ base: Base , kRange: R
43+ ) where R. Bound == Int {
44+ let range = kRange. relative ( to: 0 ..< . max)
2245 self . base = base
23- self . k = base. count < k ? - 1 : k
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
2452 }
25-
53+
54+ /// The total number of combinations.
2655 @inlinable
2756 public var count : Int {
57+ guard let k = self . kRange else { return 0 }
58+ let n = baseCount
59+ if k == 0 ..< ( n + 1 ) {
60+ return 1 << n
61+ }
62+
2863 func binomial( n: Int , k: Int ) -> Int {
2964 switch k {
3065 case n, 0 : return 1
@@ -34,9 +69,9 @@ public struct Combinations<Base: Collection> {
3469 }
3570 }
3671
37- return k >= 0
38- ? binomial ( n: base . count , k: k )
39- : 0
72+ return k. map {
73+ binomial ( n: n , k: $0 )
74+ } . reduce ( 0 , + )
4075 }
4176}
4277
@@ -46,18 +81,26 @@ extension Combinations: Sequence {
4681 @usableFromInline
4782 internal let base : Base
4883
84+ /// The current range of accepted sizes of combinations.
85+ /// - Note: The range is contracted until empty while iterating over
86+ /// combinations of different sizes. When the range is empty, iteration is
87+ /// finished.
4988 @usableFromInline
50- internal var indexes : [ Base . Index ]
89+ internal var kRange : Range < Int >
5190
91+ /// Whether or not iteration is finished (`kRange` is empty)
5292 @usableFromInline
53- internal var finished : Bool
93+ internal var isFinished : Bool {
94+ return kRange. isEmpty
95+ }
96+
97+ @usableFromInline
98+ internal var indexes : [ Base . Index ]
5499
55100 internal init ( _ combinations: Combinations ) {
56101 self . base = combinations. base
57- self . finished = combinations. k < 0
58- self . indexes = combinations. k < 0
59- ? [ ]
60- : Array ( combinations. base. indices. prefix ( combinations. k) )
102+ self . kRange = combinations. kRange ?? 0 ..< 0
103+ self . indexes = Array ( combinations. base. indices. prefix ( kRange. lowerBound) )
61104 }
62105
63106 /// Advances the current indices to the next set of combinations. If
@@ -80,24 +123,35 @@ extension Combinations: Sequence {
80123 /// // so the iteration is finished.
81124 @usableFromInline
82125 internal mutating func advance( ) {
126+ /// Advances `kRange` by incrementing its `lowerBound` until the range is
127+ /// empty, when iteration is finished.
128+ func advanceKRange( ) {
129+ if kRange. lowerBound < kRange. upperBound {
130+ let advancedLowerBound = kRange. lowerBound + 1
131+ kRange = advancedLowerBound ..< kRange. upperBound
132+ indexes. removeAll ( keepingCapacity: true )
133+ indexes. append ( contentsOf: base. indices. prefix ( kRange. lowerBound) )
134+ }
135+ }
136+
83137 guard !indexes. isEmpty else {
84138 // Initial state for combinations of 0 elements is an empty array with
85139 // `finished == false`. Even though no indexes are involved, advancing
86140 // from that state means we are finished with iterating.
87- finished = true
141+ advanceKRange ( )
88142 return
89143 }
90-
144+
91145 let i = indexes. count - 1
92146 base. formIndex ( after: & indexes[ i] )
93147 if indexes [ i] != base. endIndex { return }
94-
148+
95149 var j = i
96150 while indexes [ i] == base. endIndex {
97151 j -= 1
98152 guard j >= 0 else {
99- // Finished iterating over combinations
100- finished = true
153+ // Finished iterating over combinations of this size.
154+ advanceKRange ( )
101155 return
102156 }
103157
@@ -113,7 +167,7 @@ extension Combinations: Sequence {
113167
114168 @inlinable
115169 public mutating func next( ) -> [ Base . Element ] ? {
116- if finished { return nil }
170+ guard !isFinished else { return nil }
117171 defer { advance ( ) }
118172 return indexes. map { i in base [ i] }
119173 }
@@ -129,10 +183,78 @@ extension Combinations: Equatable where Base: Equatable {}
129183extension Combinations : Hashable where Base: Hashable { }
130184
131185//===----------------------------------------------------------------------===//
132- // combinations(count :)
186+ // combinations(ofCount :)
133187//===----------------------------------------------------------------------===//
134188
135189extension Collection {
190+ /// Returns a collection of combinations of this collection's elements, with
191+ /// each combination having the specified number of elements.
192+ ///
193+ /// This example prints the different combinations of 1 and 2 from an array of
194+ /// four colors:
195+ ///
196+ /// let colors = ["fuchsia", "cyan", "mauve", "magenta"]
197+ /// for combo in colors.combinations(ofCount: 1...2) {
198+ /// print(combo.joined(separator: ", "))
199+ /// }
200+ /// // fuchsia
201+ /// // cyan
202+ /// // mauve
203+ /// // magenta
204+ /// // fuchsia, cyan
205+ /// // fuchsia, mauve
206+ /// // fuchsia, magenta
207+ /// // cyan, mauve
208+ /// // cyan, magenta
209+ /// // mauve, magenta
210+ ///
211+ /// The returned collection presents combinations in a consistent order, where
212+ /// the indices in each combination are in ascending lexicographical order.
213+ /// That is, in the example above, the combinations in order are the elements
214+ /// at `[0]`, `[1]`, `[2]`, `[3]`, `[0, 1]`, `[0, 2]`, `[0, 3]`, `[1, 2]`,
215+ /// `[1, 3]`, and finally `[2, 3]`.
216+ ///
217+ /// This example prints _all_ the combinations (including an empty array and
218+ /// the original collection) from an array of numbers:
219+ ///
220+ /// let numbers = [10, 20, 30, 40]
221+ /// for combo in numbers.combinations(ofCount: 0...) {
222+ /// print(combo)
223+ /// }
224+ /// // []
225+ /// // [10]
226+ /// // [20]
227+ /// // [30]
228+ /// // [40]
229+ /// // [10, 20]
230+ /// // [10, 30]
231+ /// // [10, 40]
232+ /// // [20, 30]
233+ /// // [20, 40]
234+ /// // [30, 40]
235+ /// // [10, 20, 30]
236+ /// // [10, 20, 40]
237+ /// // [10, 30, 40]
238+ /// // [20, 30, 40]
239+ /// // [10, 20, 30, 40]
240+ ///
241+ /// If `kRange` is `0...0`, the resulting sequence has exactly one element, an
242+ /// empty array. The given range is limited to `0...base.count`. If the
243+ /// limited range is empty, the resulting sequence has no elements.
244+ ///
245+ /// - Parameter kRange: The range of numbers of elements to include in each
246+ /// combination.
247+ ///
248+ /// - Complexity: O(1) for random-access base collections. O(*n*) where *n*
249+ /// is the number of elements in the base collection, since `Combinations`
250+ /// accesses the `count` of the base collection.
251+ @inlinable
252+ public func combinations< R: RangeExpression > (
253+ ofCount kRange: R
254+ ) -> Combinations < Self > where R. Bound == Int {
255+ return Combinations ( self , kRange: kRange)
256+ }
257+
136258 /// Returns a collection of combinations of this collection's elements, with
137259 /// each combination having the specified number of elements.
138260 ///
@@ -159,7 +281,9 @@ extension Collection {
159281 ///
160282 /// - Parameter k: The number of elements to include in each combination.
161283 ///
162- /// - Complexity: O(1)
284+ /// - Complexity: O(1) for random-access base collections. O(*n*) where *n*
285+ /// is the number of elements in the base collection, since `Combinations`
286+ /// accesses the `count` of the base collection.
163287 @inlinable
164288 public func combinations( ofCount k: Int ) -> Combinations < Self > {
165289 assert ( k >= 0 , " Can't have combinations with a negative number of elements. " )
0 commit comments