@doc """
Returns a tuple with the popped value and the remainder of the list. The popped value is found
by the given function. Once it finds the popped value, it stops searching and returns the result.
Example:
pop_by([1, 2, 3], fn a -> a == 2 end)
> {2, [1, 3]}
# No item returns nil and unchanged list
pop_by([1, 2, 3], fn a -> a == 4 end)
> {nil, [1, 2, 3]}
"""
def pop_by(enumerable, fun), do: do_pop_by(enumerable, fun)
defp do_pop_by(enumerable, fun, collector \\ [])
defp do_pop_by([], _fun, collector), do: {nil, Enum.reverse(collector)}
defp do_pop_by([head | tail], fun, collector) do
if fun.(head) do
# found item! Reverse collector to maintain original list order and concat to tail
{head, Enum.reverse(collector) ++ tail}
else
do_pop_by(tail, fun, [head | collector])
end
end
What do you think? Could also make the collector reversal optional which would improve time complexity in cases where the order of list doesn't need to be maintained