Daniel Daniel - 1 year ago 141
Swift Question

break out of filter() function

I'd like to optimize my functions which rely on filter(). In some cases I want to break out of them when they reach a certain elements. (For example, I may have an array of distinct elements. Or, I just want to implement a kind of findFirst functionality.) In such instances it seems inefficient for the function to continue until the end of the array.

This is something very easy with loops, but I would like to apply the optimisations to functional programming principals. (The compiler wouldn't be able to perform such a optimization by itself, since it doesn't know my array and my intention.)

Can this be done?

Answer Source

filter isn’t written to break out like that. I don’t believe there’s an out-of-the-box way to do the kind of thing you’re looking for.

Generally it’s better to avoid making functions more flexible to cover narrow cases. Adding early bail might be useful sometimes but would come at the cost of complicating filter, and the code would probably be hard to read (bear in mind one of the main goals of using functions like filter, map etc is to make the code easier to read and to be certain the code is correct). Some functions do support early exit though, when it’s fundamental to their purpose - for example, contains or indexOf.

But it’s not too hard to create your own higher-order functions to do what you want, the name of which makes their intent pretty clear. For example, to take all the elements in a sequence up to the first one that doesn’t match a pattern, you could write takeWhile like this:

extension SequenceType {
    func takeWhile(condition: Generator.Element -> Bool) -> [Generator.Element] {
        var result: [Generator.Element] = []
        for x in self {
            guard condition(x) else { break }
        return result

let nums = [1,3,1,2]
let isOdd = { $0%2 == 1 }
let initialOdd = nums.takeWhile(isOdd)
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download