Reputation: 543
Say, I have an array let array = [ "foo", "bar", "baz", "foobar", "qux" ]
and an index 3 inside this array. I want to iterate all elements in the array in a following order foobar
(element at index 3), qux
(at index 4), foo
(at index 0, etc.), bar
, baz
.
Not so elegant solution would look like this:
for index in givenIndex ..< array.endIndex {
// do some work with array[index]
}
for index in array.startIndex ..< givenIndex {
// do the same work with array[index]
}
Is there a more elegant solution?
Upvotes: 1
Views: 482
Reputation: 154593
To keep from repeating your work block you could convert your ranges to arrays and add them:
let givenIndex = 3
let array = [ "foo", "bar", "baz", "foobar", "qux" ]
for index in Array(givenIndex ..< array.endIndex) + Array(0 ..< givenIndex) {
// do some work with array[index]
print(array[index])
}
Alternative Answer
Since elegant is in the eye of the beholder, another way to avoid repeating your work block is to put your ranges in an array and then select them in order before iterating over them:
for range in [givenIndex ..< array.endIndex, 0 ..< givenIndex] {
for index in range {
// do some work with array[index]
print(array[index])
}
}
Upvotes: 3
Reputation: 10091
An extension and the %
operator should work:
extension CollectionType where Index : IntegerType, Index.Distance == Index {
func offset(by: Index) -> [Generator.Element] {
guard by >= 0 else { return offset(by+count) }
return (by..<(by+count))
.map { i in self[i % count + startIndex] }
}
}
let array = [ "foo", "bar", "baz", "foobar", "qux" ]
array.offset( 1) // ["foobar", "qux", "foo", "bar", "baz"]
array.offset(-1) // ["qux", "foo", "bar", "baz", "foobar"]
let s = array.suffixFrom(2) // ["baz", "foobar", "qux"]
s.offset( 1) // ["foobar", "qux", "baz"]
s.offset(-1) // ["qux", "baz", "foobar"]
Upvotes: 3