Finding the first matching object in a collection, functionally

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Finding the first matching object in a collection, functionally

Jens Alfke
A couple of times I’ve had the need to find the first (or just any) element of a collection that passes some test. Of course the traditional way to do this is to run a ‘for’ loop over the collection, test each element, and break when you find the match. But I wanted to do it functionally.

There doesn’t seem to be an existing operator for this. There’s a first( ) function but it just returns the first item in a collection. The closest thing I can find is to use filter( ) and then take the first element of the result, e.g.:
        let bob = people.filter({$0.firstName == “bob”}).first
At first glance this looks inefficient — what if there are zillions of items that match the test? — but reading between the lines I’m guessing that filter may be lazy, generating items on demand, so stopping after the first one means the test would only succeed once. Is that true?

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/982ACBF2-1026-4575-9BC5-BE48021FDFC4%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Finding the first matching object in a collection, functionally

Brent Royal-Gordon-2
Regular filter() is not lazy, but the Swift standard library supports lazy Sequences:

    lazy(people).filter { your test here }

Unfortunately, there's no way to first() the resulting Sequence, but that's easy to write:

    func first<Seq: SequenceType>(seq: Seq) -> Seq.Generator.Element? {
        var generator = seq.generate()
        return generator.next()
    }

HTH,
—Brent


On Thu, May 21, 2015 at 2:44 PM Jens Alfke <[hidden email]> wrote:
A couple of times I’ve had the need to find the first (or just any) element of a collection that passes some test. Of course the traditional way to do this is to run a ‘for’ loop over the collection, test each element, and break when you find the match. But I wanted to do it functionally.

There doesn’t seem to be an existing operator for this. There’s a first( ) function but it just returns the first item in a collection. The closest thing I can find is to use filter( ) and then take the first element of the result, e.g.:
        let bob = people.filter({$0.firstName == “bob”}).first
At first glance this looks inefficient — what if there are zillions of items that match the test? — but reading between the lines I’m guessing that filter may be lazy, generating items on demand, so stopping after the first one means the test would only succeed once. Is that true?

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/982ACBF2-1026-4575-9BC5-BE48021FDFC4%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/CAEeRk-brBpRjrb5jToT7N2BoLuZzQRA83cDS%2Bcy10JV1JFFfqA%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Finding the first matching object in a collection, functionally

Jens Alfke
Thanks! But if I’m going to write custom code to do this, I think I’d just rather write a function that iterates the collection and returns the first matching element, since it’s simpler and probably faster.

—Jens

--
You received this message because you are subscribed to the Google Groups "Swift Language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
To post to this group, send email to [hidden email].
To view this discussion on the web visit https://groups.google.com/d/msgid/swift-language/781843E0-905B-4BE5-9FA5-CD6F5FDB4B04%40mooseyard.com.
For more options, visit https://groups.google.com/d/optout.