My code:
let range = 30...200 //ranges may have different bounds
let index = range.firstIndex(of: 55)
The problem is index
has type ClosedRange<Int>.Index
and it is unclear how to convert it to Int
now for further usage.
I understand that it is simplier to convert range to array and look for int index in it but they somehow should allow to use ClosedRange<Int>.Index
by itself
Note: there are may be similar questions but all of them about how to convert ClosedRange<Int>
to an array, not index conversion
ClosedRange<Bound>.Index
is literally just an enum that doesn't tell you anything useful.
enum Index {
case inRange(Bound)
case pastEnd
}
Something as simple as this is enough to correctly implement the index-related methods that Collection
and other protocols require.
firstIndex(of: 55)
would return inRange(55)
if 55 is in the range, and pastEnd
otherwise.
Also note that firstIndex
(and other Collection
methods) is only available when Bound
conforms to Stridable
and the Stride
conforms to SignedInteger
. After all, it doesn't make sense to treat a ClosedRange<Double>
or a ClosedRange<String>
as a Collection
.
So the only ranges where an operation like firstIndex(of: 55)
makes sense, is when Bound: Stridable, Bound.Stride: SignedInteger
. You can find out the "numeric" index of an element in such a range by using distance(to: lowerBound)
, which is a method on Stridable
.
extension ClosedRange where Bound: Strideable, Bound.Stride: SignedInteger {
func numericIndex(of element: Bound) -> Bound.Stride? {
if contains(element) {
return element.distance(to: lowerBound)
} else {
return nil
}
}
}
For ClosedRange<Int>
, this is basically subtraction. The index of 55 in 30...200 is simply 55 - 30 = 25.