Ryan Heitner
Ryan Heitner

Reputation: 13632

is there a more elegant syntax for Swift Filter with 2 parameters

Is there a more elegant way to filter with an additional parameter (or map, reduce).

When I filter with a single parameter, we get a beautiful easy to ready syntax

let numbers = Array(1...10)

func isGreaterThan5(number:Int) -> Bool {
    return number > 5
}

numbers.filter(isGreaterThan5)

However, if I need to pass an additional parameter to my function it turns out ugly

func isGreaterThanX(number:Int,x:Int) -> Bool {
    return number > x
}

numbers.filter { (number) -> Bool in
    isGreaterThanX(number: number, x: 8)
}

I would like to use something like

numbers.filter(isGreaterThanX(number: $0, x: 3))

but this gives a compile error annonymous closure argument not contained in a closure

Upvotes: 3

Views: 991

Answers (1)

Martin R
Martin R

Reputation: 539945

You could change your function to return a closure which serves as predicate for the filter method:

func isGreaterThan(_ lowerBound: Int) -> (Int) -> Bool {
    return { $0 > lowerBound }
}

let filtered = numbers.filter(isGreaterThan(5))

isGreaterThan is a function taking an Int argument and returning a closure of type (Int) -> Bool. The returned closure "captures" the value of the given lower bound.

If you make the function generic then it can be used with other comparable types as well:

func isGreaterThan<T: Comparable>(_ lowerBound: T) -> (T) -> Bool {
    return { $0 > lowerBound }
}

print(["D", "C", "B", "A"].filter(isGreaterThan("B")))

In this particular case however, a literal closure is also easy to read:

let filtered = numbers.filter( { $0 > 5 })

And just for the sake of completeness: Using the fact that Instance Methods are Curried Functions in Swift, this would work as well:

extension Comparable {
    func greaterThanFilter(value: Self) -> Bool {
        return value > self
    }
}

let filtered = numbers.filter(5.greaterThanFilter)

but the "reversed logic" might be confusing.


Remark: In earlier Swift versions you could use a curried function syntax:

func isGreaterThan(lowerBound: Int)(value: Int) -> Bool {
    return  value > lowerBound
}

but this feature has been removed in Swift 3.

Upvotes: 8

Related Questions