elixir is an immutable language. One cannot change the value of a variable. Ever.
One might rebind a variable, but it would never leak to the outer scope, so what are you doing is basically binding rangeN in an internal scope to immediately discard it. The variable (having the same name by coincidence) from the outer scope never gets changed.
We don’t have loops in elixir either. We use map/reduce instead.
That said, what you need is Enum.reduce/3
Enum.reduce(
[1,11,2,22,33,23], # input
{0, 0, 0, 0}, # initial accumulator
fn x, {acc1, acc2, acc3, acc4} ->
cond do
x>=1 and x<=10 -> {acc1 + 1, acc2, acc3, acc4}
x>=11 and x<=20 -> {acc1, acc2 + 1, acc3, acc4}
x>=21 and x<=30 -> {acc1, acc2, acc3 + 1, acc4}
x>=31 and x<=40 -> {acc1, acc2, acc3, acc4 + 1}
end
end)
#⇒ {2, 1, 2, 1}
The function always returns the result of the last expression, hence we are to use cond/1 here. But the idiomatic way would be to have multiple clauses of the accumulating function with guards.
Enum.reduce [1,11,2,22,33,23], {0, 0, 0, 0}, fn
x, {acc1, acc2, acc3, acc4} when x>=1 and x<=10 ->
{acc1 + 1, acc2, acc3, acc4}
x, {acc1, acc2, acc3, acc4} when x>=11 and x<=20 ->
{acc1, acc2 + 1, acc3, acc4}
x, {acc1, acc2, acc3, acc4} when x>=21 and x<=30 ->
{acc1, acc2, acc3 + 1, acc4}
x, {acc1, acc2, acc3, acc4} when x>=31 and x<=40 ->
{acc1, acc2, acc3, acc4 + 1}
end
To get to the values one might either pattern match the result or use Kernel.elem/2.
{less_that_10, _, _, _} =
Enum.reduce(...)
less_than_10
#⇒ 2
input
|> Enum.reduce(...)
|> elem(0)
#⇒ 2