Iterate over all elements in the array in order starting given index

Roman Busygin Source

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?

arraysswift

Answers

answered 3 years ago oisdk #1

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"]

answered 3 years ago vacawama #2

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])
    }
}

comments powered by Disqus