Do something x number of times

(where x is an integer >= 0)

Is there a one-liner for this?

I found that Enum.times was deprecated back in in 2012:

But it seems that ranges aren’t a proper replacement, since they don’t work for the case where x == 0.

1 Like

Ranges work fine with 0.

Enum.each(0..x, fn i -> do_something(i) end)
3 Likes

If you mean the specific case of 0..0, it can be dealt with like this

Enum.each(0..x, fn
  0 -> :nothing
  _ -> do_something()
end)
3 Likes

Right, I was just wondering if there was something that more directly replaced Enum.times that I missed. Thanks!

1 Like
iex(5)> for i <- 0..10, i > 0, do: IO.puts i
1
2
3
4
5
6
7
8
9
10
[:ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok, :ok]
iex(6)> for i <- 0..0, i > 0, do: IO.puts i 
[]
7 Likes

Yeah that’s more what I was looking for. Thanks!

1 Like

Keep in mind that the intent of comprehensions is to work with Enumerables which Range happens to implement. Hence the “result” of the comprehension is a list of :ok values; in this particular case the side-effect is the intended behaviour.

Now you can suppress the list of :ok values by abusing the filter expression:

iex(1)> for x <- 0..10, (fn i -> if (i > 0), do: IO.puts i; false end).(x), do: :ok       
1
2
3
4
5
6
7
8
9
10
[]

But that’s really going from bad to worse.

There is nothing stopping you from creating your own “one-liner”:

iex(2)> do_it = fn (low,high,f) ->
...(2)>    aux = fn
...(2)>      c,i when i <= high ->
...(2)>        f.(i)
...(2)>        c.(c, i+1)
...(2)>      _,_ ->
...(2)>        :ok 
...(2)>    end
...(2)>    aux.(aux,low)  
...(2)>  end 
#Function<18.99386804/3 in :erl_eval.expr/5>
iex(3)> do_it.(0,10,&IO.puts/1)     
0
1
2
3
4
5
6
7
8
9
10
:ok
iex(4)> 

Otherwise I’d just stick with Enum.each/2.

1 Like

It appeared that Range type in Elixir has step:

iex(1)> Map.from_struct(1..0)
%{first: 1, last: 0, step: -1}

So it’s possible to overcome the “do nothing” problem via this range creation syntax:

for _ <- 1..n//1, do: something()

This loop will call something() n times, and will NOT call it at all when n == 0

See Range — Elixir v1.13.4 for more examples

2 Likes

Stream.repeatedly(...) |> Enum.take(n)

Or Stream.iterate if you really just want increments.

1 Like