If I have a Range, say
let bilbo = ( 1 ... 5 )
And I wanted to advance all elements of it by a number, say 3, is there a way other than
let offset = 3
let baggins = ( bilbo.first! + offset ... bilbo.last! + offset )
Something like
bilbo.advance_by( 3 )
Which I discovered only works for one element in the Range?
I have searched the web and SO and can't find an answer. I'm guessing that there is a Swift-ish way to do this that probably appears in another SO post somewhere that I just don't comprehend how it connects yet. Any help would be appreciated.
let advanceRangeBy : (Range<Int>, Int) -> Range<Int> = { $0.0.first!.advancedBy($0.1) ... $0.0.last!.advancedBy($0.1) }
let bilbo = 1...5
let bagger = advanceRangeBy(bilbo, 3) // 4..<9
You can also make it a generic extension to Range that will work for many (although not all) types of Range:
let bilbo = 1...5
extension Range where Element : BidirectionalIndexType {
func advanceRangeBy(advance: Element.Distance) -> Range<Element> {
return first!.advancedBy(advance) ... last!.advancedBy(advance)
}
}
let baggins = bilbo.advanceRangeBy(3)
For the sake of completeness, I thought I'd add that you can also perform this range advancement/de-advancement operation using a custom binary infix operator
infix operator <> {
associativity left
precedence 140 /* use same precedence as '+', '-' arithmetic */
}
func <> (lhs: Range<Int>, rhs: Int) -> Range<Int>{
var out : Range<Int> = lhs
out.endIndex = lhs.endIndex + rhs
out.startIndex = lhs.startIndex + rhs
return out
}
let bilbo = 1...5
let bagger = bilbo <> 3 // 4..<9
let frodo = bagger <> (-2) // 2..<7
How about a simple extension:
extension Range {
public func advancedBy(n: Element.Distance) -> Range<Element> {
let startIndex = self.startIndex.advancedBy(n)
let endIndex = self.endIndex.advancedBy(n)
return Range(start: startIndex, end: endIndex)
}
}
Update for swift 5:
public extension CountableRange {
func advanced(by n: Bound.Stride) -> Self {
let lowerBound = self.lowerBound.advanced(by: n)
let upperBound = self.upperBound.advanced(by: n)
return .init(uncheckedBounds: (lowerBound, upperBound))
}
static func + (lhs: Self, rhs: Bound.Stride) -> Self {
lhs.advanced(by: rhs)
}
}
Note that CountableRange is just a typealias for Range with conditions:
typealias CountableRange<Bound> = Range<Bound> where Bound : Strideable, Bound.Stride : SignedInteger
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With