如何在elixir的循环中增加一个值
我正在尝试计算从 range1 到 range4 的每个范围内数字的次数。范围1是1-10,范围2是11-20,范围3是21-30,范围4是31-40。我在下面的是:
range1=0
range2=0
range3=0
range4=0
arr=[1,11,2,22,33,23]
Enum.each arr, fn(x) ->
if x >=1 and x<=10 do
range1=range1+1
end
if x>=11 and x<=20 do
range2=range2+1
end
if x>=21 and x<=30 do
range3=range3+1
end
if x>=31 and x<=40 do
range4=range4+1
end
end
IO.puts range1
IO.puts range2
IO.puts range3
IO.puts range4
但是,当我运行它时,它会说它们都是 0。为什么要这样做?
回答
Elixir是一种不可变的语言。不能改变变量的值。曾经。
人们可能会重新绑定一个变量,但它永远不会泄漏到外部作用域,所以您所做的基本上是rangeN 在内部作用域中绑定以立即丢弃它。来自外部作用域的变量(巧合地具有相同的名称)永远不会改变。
我们在elixir 中也没有循环。我们改用 map/reduce。
也就是说,你需要的是 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}
该函数总是返回最后一个表达式的结果,因此我们在cond/1这里使用。但是惯用的方法是使用带有警卫的累积函数的多个子句。
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
要获取值,可以使用模式匹配结果或使用Kernel.elem/2.
{less_that_10, _, _, _} =
Enum.reduce(...)
less_than_10
#? 2
input
|> Enum.reduce(...)
|> elem(0)
#? 2