First element of iteration satisfying a predicate

I often find that I want to use something like findfirst on iterables that have no (or inefficient) random access, something like

function satisfies_first(predicate, itr)
    for i in itr
        predicate(i) && return Some(i)
    end
    nothing
end

julia> satisfies_first(iseven ∘ first, ((i, 2*i) for i in 1:10))
Some((2, 4))

It is pretty trivial to code this, but does this exist in a package somewhere? Or Base? I found this discussion about something similar, but I want to be careful about corner cases (element not found).

1 Like

Possibly just chain Iterators.filter(==(5), [1 2 3 4 5]) |> x -> isempty(x) ? nothing : first(x)?

1 Like

Sure, but that’s quite a mouthful for something so basic (and also note that it should give back Something(first(x))).

I will wait for more replies, then consider contributinga function not unlike the above to

1 Like

Maybe a bit nicer:

itr = ((i, 2i) for i in 1:10)
predicate = isodd ∘ first

using Base.Iterators
first(dropwhile(predicate, itr))

But this breaks if the collection is empty (there is no first to collect). Yea, nm. I’ll post this anyways…

I would perhaps define the generally useful

function someiterate(iter)
           ϕ = iterate(iter)
           ϕ === nothing && return nothing
           return Some(first(ϕ))
       end

instead and then it becomes

someiterate(dropwhile(predicate, itr))

you stay a bit longer in the “iterator-world”

3 Likes

People seemed open to the idea of adding that kind of functionality to Base, but I didn’t pursue it through until the PR was merged.

3 Likes