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.