I’m wondering if the following functions already exist in Julia with another name? I’m often trying to grab a single element, so I find myself writing filter(...) -> first a lot, but this is not safe because if the filter call returns an empty array, then I need to handle that case. c# has a linq function call Single() which returns the single object which satisfies the criteria, if more than one element match an exception is returned, otherwise nothing is returned.
function filterfirst(f,items)
for item in items
if f(item)
return item
end
end
return nothing
end
function filtersingle(f,items::Vector{T}) where T
found = T[]
for item in items
if f(item)
push!(found, item)
end
end
n = length(found)
if n == 0
return nothing
elseif n == 1
return found[1]
elseif n > 1
error("Found $n items, expected 1")
end
end
filter(f, a) |> fila -> get(fila, firstindex(fila), nothing)
but your version is more efficient since it returns immediately on finding a match.
For filtersingle, instead of collecting all items and then checking at the end, you can collect just the one item you might want to return, and error immediately if there’s more than one.
julia> function filtersingle(f,items::Vector{T}) where T
local found::T
for item in items
if f(item)
@isdefined(found) && error("Found more than one matching item")
found = item
end
end
return (@isdefined(found) ? found : nothing)
end
I’m guessing I can answer this myself: Without the exception it would be impossible to discern if a collection is empty or if it simply has Nothing as its first element.
So it seems if we want the functionality of filterfirst or filtersingle, one must write their own function or combined expression. Is this worth a PR to include in the Julia language?
I don’t think it’s worth opening a PR—as I noted above, (unlike for findfirst) there is no obvious behavior for filterfirst when the collection has no matching element. So it is unlikely that folks will come to an agreement about the implementation
My thinking is findfirst returns nothing when no match exists, therefore fitlerfirst would do the same thing.
The find.. functions are for returning indexes, the filter.. functions are for returning the elements. Just seems to me like a missing feature. Other languages implement such a thing.
So now it’s unclear: Did I find a matching element which happens to have the value nothing? Or was there no matching element at all? And, in the first place, why should the return value “no matching element” be nothing rather than missing?
I think the accepted way to handle this in Base is to return a Union{Some{T}, Nothing}. However, I’m not sure if any functions in the public API for Base/stdlib Julia have actually adopted this approach…