How can I break out of a Enum.reduce in elixir

Viewed 4382

I want to find the sum of all positive number that come before first negative number.

I got the following list in elixir.

iex(4)> steps = [0,1,2,3,-4,5,6,-1]

And I calculate the sum of this list as follows

Enum.reduce(steps,0,fn x,acc -> acc=acc+x end)

How to come out of reduce once we hit a negative number?

4 Answers

You can use Enum.take_while/2

Takes the items from the beginning of the enumerable while fun returns a truthy value.

Enum.take_while([0, 1, 2, 3, -4, 5, 6, -1], fn(x) -> x >= 0 end) |> Enum.sum

=> 6

Or use the shorthand

list = [0, 1, 2, 3, -4, 5, 6, -1]
Enum.take_while(list, &(&1 >= 0)) |> Enum.sum

Answers here lack a recursion solution, here it is:

defmodule M do                          
  @steps [0,1,2,3,-4,5,6,-1]

  def sum(list, acc \\ 0)
  def sum([], acc), do: acc
  def sum([h|_], acc) when not is_number(h), do: :error
  def sum([h|_], acc) when h < 0, do: acc
  def sum([h|t], acc), do: sum(t, acc + h)

  def sum_steps(), do: sum(@steps)
end

M.sum_steps()
#⇒ 6

in Erlang syntax:

1> L = [1,2,3,-4,5,6,-1].
[1,2,3,-4,5,6,-1]
2> lists:foldl(fun(X,{S,true}) when X >= 0 -> {S+X,true}; (_,{S,_}) -> {S,false} end,{0,true},L).
{6,false}

Of course this function will parse the complete list even if the first element is negative. A simple "hand made" code will avoid this:

3> SW = fun SW([H|T],S) when H >= 0 -> SW(T,S+H); SW(_,S) -> S end.
#Fun<erl_eval.36.127694169>
4> SumWhilePos = fun(P) -> SW(P,0) end.
#Fun<erl_eval.6.127694169>
5> SumWhilePos(L).
6
Related