magnuskahr

writing code

Iterating over two sequences in Swift

Lately, I have been playing a lot of chess, and the other day, I needed an app to play multiplayer on a single iPad - it turns out I did not find I good app for this. So what we do as developers is, that we develop it ourselves!

I came to an interesting situation, where I needed to loop over two different arrays at once.

In chess, the board is build of rows and columns, but in chess we call this for rank and files. They are represented using enums.

enum Rank: Int, CaseIterable {
    case one = 1
    case two
    case three
    case four
    case five
    case six
    case seven
    case eight
} 

and

enum File: Int, CaseIterable {
    case a = 1
    case b	  
    case c
    case d
    case e
    case f
    case g
    case h
}

The case for this situation, was when I needed to calculate the paths the bishop fx. could take diagonally. Let us say I wanted to calculate the path, that a bishop could take down to the left.

let files = File.allCases.filter { $0 < from.file }.reversed()
let ranks = Rank.allCases.filter { $0 < from.rank }.reversed()

First I would collect all the files to the left of the bishop, and then all the ranks under the bishop. There could simply be a situation where these two arrays would not be of the same size, so a simple iteration with index would not work, one could though fix it:

for i ..< Swift.min(files.count, ranks.count) {
    let file = files[i]
    let rank = ranks[i]
} 

But I think we all can agree this is a sad, boring and ugly solution. Let us Swift it up!

Let me introduce zip()

It turns out, that Swift have an awesome function called zip() which takes two types of SequenceType and then lets you iterate over over them together! So now we can do something like this:

for (file, rank) in zip(files, ranks) {
    let position = Position(file: file, rank: rank)
    print(position)
}

Read more about the zip function over at Apple's official Swift documentation.