How can I run through three separate arrays in the same for loop?

This is a very common requirement so the standard library caters to it with a function, zip:*

for (a,b) in zip(seq1, seq2) {
    // a and b will be matching pairs from the two sequences
}

Unfortunately, as of right now, zip only does pairs, even though in theory it could be overloaded to do triples. However, it’s not a big deal, you can just nest them:

var names = ["Joe", "Sarah", "Chad"]
var ages = [18, 20, 22]
var genders: [Gender] = [.Male, .Female, .Male]

for (name,(age,gender)) in zip(names,zip(ages,genders)) {
    makeUser(name, userAge: age, userGender: gender)
}

Note, it will only serve up to the shortest sequence, so if there are more names than ages or genders, you’ll only get the matching names.

This might seem like a down side compared to using an index, and this might also seem more complex, but the alternative’s simplicity is deceptive. Bear in mind what would happen if you used indices or enumerate alongside arrays that didn’t match – you’d get an array out of bounds assertion (or you’d have to put in checking logic).

zip avoids this problem. It also means you can use sequences instead of collections, as well as working with collections that don’t have integer indices (unlike enumerate) or collections that have different index types (e.g. a String and an Array).

*(in the current beta, anyway – zip returns a Zip2 object. In Swift 1.1, you need to create the Zip2 version directly as zip has only just been introduced)

Leave a Comment