Swift 2: “for… in” filtering

While looking through slides for What’s New in Swift again, I’ve decided to instead play around with and write down the new Swift 2 idioms here for easy reference for myself (and hopefully others). This post focusses on the “for… in” filtering:

The Concept

The idea behind “for… in” filtering is that now you can do filters inline vs in your for loop. So instead of this:


let numbers = [1,2,3,4,5,6,7,8,9,10]

// BS2 (Before Swift 2)

for number in numbers {
    if number % 2 == 0 {
        print(number)
    }
}

You can now do this!

let numbers = [1,2,3,4,5,6,7,8,9,10]

// Swift 2

for number in numbers where number % 2 == 0 {
    print(number)
}

“for… in” + Pattern Matching

Note that you can use the pattern matching with “if case” in combination with the for…in filtering for some even more advanced filtering! Here is one example:

let taylorSwiftAlbumsWithYear = [
    ("Red", 2014),
    ("1989", 2014),
    ("Fearless", 2008),
    ("Speak Now", 2008)]

for case let (album, 2014) in taylorSwiftAlbumsWithYear {
    print("Taylor Swift's album \(album) was released in 2014")
}

// printed:
// Taylor Swift's album Red was released in 2014
// Taylor Swift's album 1989 was released in 2014

Filtering with Enum

Finally, you can filter enum values like this:

enum MyEnum {
    case MyEnumCase(String)
    case MyOtherEnumCase(String)
}

let enumValues = [MyEnum.MyEnumCase("someValue"),
    MyEnum.MyEnumCase("someOtherValue"),
    MyEnum.MyOtherEnumCase("NatashaTheRobot was here")]

for case let .MyEnumCase(value) in enumValues {
    print(value)
}

// someValue
// someOtherValue

Note here that the let outside the enum case refers to the value inside 🙁 I hope the Swift team updates this syntax to be what they had in their slides:

// MORE READABLE IMO, BUT DOES NOT WORK
for case .MyEnumCase(let value) in enumValues {
    print(value)
}

Filtering Optionals

An implication of filtering of enum values is that you can now filter Optionals:

let numbersWithOptions: [Int?] = [nil, 1,2,4, nil, 6]

for case let .Some(number) in numbersWithOptions where number % 2 == 0 {
    print(number)
}

But of course you should use the version using the new shorthand syntax for .Some(let number):

let numbersWithOptions: [Int?] = [nil, 1,2,4, nil, 6]

for case let number? in numbersWithOptions where number % 2 == 0 {
    print(number)
}

// 2,4,6

If you’re confused by the ? in theAnswer?, see my blog post on the new unwrapping optionals with pattern matching.

This still doesn’t feel natural to me. I’ll have to look back on this blog post a few times as I’m refactoring my code for Swift 2!

Enjoy the article? Join over 14,500+ Swift developers and enthusiasts who get my weekly updates.

  • wottpal

    This is working for me, but not with the “let” inside…

    for case let .MyEnumCase(value) in enumValues {
    print(value)
    }

    • Thanks for figuring it out. Hate that the let is on the outside. Yuk! Hope they fix it before the GM.

      • wottpal

        It’s working now inside too 😉

      • Mark Beaty

        Yep, works now in Swift 2.1.

    • Thanks again. Updated the blog post using the let on the outside.

  • Hi Natasha, thanks for this useful post. I personally find a bit “confusing” when things don’t have much consistency to them.

    One particular example is with for case let (album, 2014) in taylorSwiftAlbumsWithYear in your example. If I am not mistaken, there’s a conditional variable unwrapping going on there + pattern matching, as in album will be kept as a variable, whilst year (the second item in the tuple) will be unwrapped and matched against 2014. Now, that’s neat and all, but again, I (personally) find it too much magic.

    How would you compare it with for case let (album, year) in taylorSwiftAlbumsWithYear where year == 2014 instead?

    I am curious to hear whatever thoughts (or correcting my silly mistakes) you might have…

    Thank you!