Here's a type I'm trying out:
/// A collection of all the combinations of a certain count of values within a
/// range.
///
/// - Warning: The element count may exceed `Int.max`. In this case, both
/// `count` and anything that depends on it won't work. All other operations
/// from both `Collection` and `Sequence` should work. Whether `count` is
/// usuable can be checked by seeing if `underestimatedCount` is below
/// `Int.max`.
public struct RangeCombinations<Bound: Strideable>
: BidirectionalCollection, LazyCollectionProtocol
where Bound.Stride: SignedInteger
{ /*...*/ }
extension Range where Bound: Strideable, Bound.Stride: SignedInteger {
/// Returns each subset of strictly-increasing values from this range, as a
/// lazy collection of arrays with the given length.
///
/// Elements are taken out of the range without repetition.
///
/// - Parameter k: The number of values to use per returned array.
/// - Returns: A lazy collection of all the combinations.
@inlinable
public func combinations(ofLength k: Int) -> RangeCombinations<Bound> {
return RangeCombinations(self, choiceLength: k)
}
}
I originally had this type as a Sequence
, but since I can rationally go from one element to another, in either direction, it's more spiritually of a Collection
. The problem is that
(0..<100).combinations(ofLength: 50)
is in the nonillion range, while Int
can only go up into the quintillion range. As long as a few methods as possible touch count
, I would seem to be golden. (Methods within the Collection
hierarchy that are customization points can be overridden if need be.)