我对 Elixir 非常陌生
运行总计变量在运行后重置为零 if 语句。我该如何解决这个问题?
我知道 Elixir 中的一切都是“不可变的”,但我知道 并没有真正帮助我。
defmodule Solution do
@spec roman_to_int(s :: String.t) :: integer
def roman_to_int(s) do
roman_map = %{
"I" => 1,
"V" => 5,
"X" => 10,
"L" => 50,
"C" => 100,
"D" => 500,
"M" => 1000
}
running_total = 0
max_value = -100
s = String.reverse(s)
IO.puts("String is now: #{s}")
String.graphemes(s) |> Enum.each(fn char ->
curr_val = roman_map[char]
IO.puts("processing char: #{char}")
if curr_val >= max_value do
running_total = running_total + curr_val
IO.puts("greater than, running total is now: #{running_total}")
end
IO.puts("after greater than, running total is now: #{running_total}")
if curr_val < max_value do
running_total = running_total - curr_val
IO.puts("less than, running total is now: #{running_total}")
end
if curr_val > max_value do
max_value = curr_val
end
end)
running_total
end
end
IO.puts(Solution.roman_to_int("XIV"))
“一切都是一成不变的”实际上是最重要的一句话。每次分配给一个变量时,它都会创建一个新变量,如果它位于 lambda 或像
if
表达式这样的块内,则新变量的作用域为该块。
在机械层面上,这意味着,如果你想“重新分配”一个变量,你需要覆盖两个分支 if
if
表达式(在 Elixir 中它是一个表达式而不是语句)并分配结果.
running_total = if curr_val >= max_value do
running_total + curr_val
else
running_total
end
然而,lambda 也存在类似的问题。 lambda 无法修改外部作用域的变量,因此需要从 lambda 函数返回新状态。
Enum.reduce/3
采用初始状态并允许函数返回新状态。
我该如何修改这个?匿名函数保留两个运行状态,您将其标记为
running_total
和 max_value
。您需要将它们作为函数的参数,并从函数返回更新的值。 Enum.reduce/3
将返回最终状态。
{running_total, _} = String.graphemes(s)
|> Enum.reduce({0, -100}, fn char, {running_total, max_value} ->
...
{running_total, max_value}
end)
running_total
在函数内,您需要确保重新分配变量,无论采用
if
条件的哪条路径。
running_total = if curr_val >= max_value do
running_total + curr_val
else
running_total - curr_val
end
max_value = max(curr_val, max_value)
请注意,
max_value
不存在于匿名函数之外。函数体无法修改它,并且它不是最终返回的一部分。作为 reduce
调用迭代之间传递的状态的一部分,它确实会返回,但可以在那里忽略。