Standard way to get first element of iterator satisfying predicate

I have a collection and want to get the first element satisfying predicate p.
One way I can achieve it is first(x for x in col if p(x)) but I thought maybe there is more standard way, something such first(p, col).
What is the common way to do it?

Are you looking for findfirst?

julia> x = [3,4,2,9,1,8,1,2,3,4]
10-element Array{Int64,1}:
 3
 4
 2
 9
 1
 8
 1
 2
 3
 4

julia> findfirst(x -> x > 5, x)
4

No, I want the element itself, no its index (col is iterable, not necessarily an array).

You could do:

julia> x = [3,4,2,9,1,8,1,2,3,4]
10-element Array{Int64,1}:
 3
 4
 2
 9
 1
 8
 1
 2
 3
 4

julia> first(Iterators.filter(x -> x > 5, x))
9

This will error if there is no element satisfying the predicate.

I immediately thought that naturally there’s a way to do this. But I cannot find it now.

So I made my own simple one that is fast and returns nothing if appropriate:

function getfirst(p, itr)
    for el in itr
        p(el) && return el
    end
    return nothing
end
1 Like

first(Iterators.filter(call, iterator))

The way you are doing it seems fine. The if statement you add to the generator cretes a, filter iterator so the suggestions with Iterators.filter are equivalent to what you already have.

2 Likes

I have literally exactly this function everywhere in my codes too :smiley: (name and behavior)

1 Like

In case you aren’t aware, this is a good case for Some. It allows distinguishing found vs not found in e.g. the case getfirst(a -> isnothing(a) || ismissing(a), ...).

2 Likes

Thank you all! I think first(Iterators.filter(...)) isn’t more readable and ofcourse, it’s not shorter, so I continue to use first + generator. I hope that in the future there will be dedicated function for this.

1 Like

Why do we need to use iterators for this?

You could use filter instead of Iterators.filter, but the first one allocates a new array, which will be very inefficient. The Iterators submodule provides different lazy iterators, which can be more efficient in some situations than working with arrays.

1 Like

So what is the way to get the first element of an iterator satisfying some predicate or nothing at the moment? I use

 iterate(x for x in l if p(x))

but I am still on 1.1 and there may be new ways to catch an empty iterator on1.5?

1 Like