如何在长生不老药的循环中增加一个值
How to increment a value in a loop in 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 中也没有 loops。我们使用 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}
函数总是returns最后一个表达式的结果,因此我们在这里使用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
when I run it, it'll say that they're all 0. Why is it doing that?
Elixir 中的变量绑定到当前范围。如果您绑定到函数内部的变量(例如您在代码中传递给 Enum.each/2
的匿名函数),则该变量仅在该函数内部可用。尽管您在匿名函数中分配给 range1
,但它与您在文件顶部定义的 range1
完全不同,它始终是 0
.
How to increment a value in a loop in elixir
这是错误的思考方式。您需要考虑的是处理列表。对于你的情况,我认为结合 Enum.frequencies_by/2
with guards and ranges 是一个很好的解决方案:
Enum.frequencies_by([1, 11, 2, 22, 33, 23], fn
i when i in 1..10 -> :range1
i when i in 11..20 -> :range2
i when i in 21..30 -> :range3
i when i in 31..40 -> :range4
end)
这会产生:
%{range1: 2, range2: 1, range3: 2, range4: 1}
如果我可以假设你的范围是固定的,并且你的输入大于零,我提出这个解决方案:
[range1,range2,range3,range4] =
for elem <- arr, reduce: [0,0,0,0] do
answer ->
update_in(answer, [Access.at!(div((elem - 1), 10))], &(&1 + 1))
end
Access.at!() 会方便地为输出数组范围之外的索引抛出异常。换句话说,输入 45 将生成索引 4,这超出了 [0,0,0,0]
的索引范围
我正在尝试计算从 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 中也没有 loops。我们使用 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}
函数总是returns最后一个表达式的结果,因此我们在这里使用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
when I run it, it'll say that they're all 0. Why is it doing that?
Elixir 中的变量绑定到当前范围。如果您绑定到函数内部的变量(例如您在代码中传递给 Enum.each/2
的匿名函数),则该变量仅在该函数内部可用。尽管您在匿名函数中分配给 range1
,但它与您在文件顶部定义的 range1
完全不同,它始终是 0
.
How to increment a value in a loop in elixir
这是错误的思考方式。您需要考虑的是处理列表。对于你的情况,我认为结合 Enum.frequencies_by/2
with guards and ranges 是一个很好的解决方案:
Enum.frequencies_by([1, 11, 2, 22, 33, 23], fn
i when i in 1..10 -> :range1
i when i in 11..20 -> :range2
i when i in 21..30 -> :range3
i when i in 31..40 -> :range4
end)
这会产生:
%{range1: 2, range2: 1, range3: 2, range4: 1}
如果我可以假设你的范围是固定的,并且你的输入大于零,我提出这个解决方案:
[range1,range2,range3,range4] =
for elem <- arr, reduce: [0,0,0,0] do
answer ->
update_in(answer, [Access.at!(div((elem - 1), 10))], &(&1 + 1))
end
Access.at!() 会方便地为输出数组范围之外的索引抛出异常。换句话说,输入 45 将生成索引 4,这超出了 [0,0,0,0]
的索引范围