Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 基于另一个嵌套贴图迭代更新贴图_Elixir - Fatal编程技术网

Elixir 基于另一个嵌套贴图迭代更新贴图

Elixir 基于另一个嵌套贴图迭代更新贴图,elixir,Elixir,《长生不老药》中的不变性真的让我大吃一惊,让语言使用起来如此混乱。我需要迭代一个嵌套映射,并根据迭代简单地更新一些计数,但是Enum.reduce只会让我感到困难。假设我有: defmodule Predictor do def past_matches() do [ team1: %{team2: %{f: 0, a: 1}, team3: %{f: 1, a: 3}}, team2: %{team1: %{f: 3, a: 0}, team3: %{

《长生不老药》中的不变性真的让我大吃一惊,让语言使用起来如此混乱。我需要迭代一个嵌套映射,并根据迭代简单地更新一些计数,但是
Enum.reduce
只会让我感到困难。假设我有:

defmodule Predictor do

  def past_matches() do
    [
      team1: %{team2: %{f: 0, a: 1},  team3: %{f: 1, a: 3}},
      team2: %{team1: %{f: 3, a: 0},  team3: %{f: 2, a: 0}},                    
      team3: %{team1: %{f: 1, a: 0},  team2: %{f: 0, a: 1}},
    ]
  end


  def init_indexes(matches) do
    local = Enum.reduce matches, %{}, fn({team, _scores}, acc) ->
      Map.put acc, team, %{f: 0, a: 0, n_games: 0}
    end

    Enum.each matches, fn({team, scores}) ->
      Enum.each scores, fn({vteam, %{f: ff, a: aa}}) ->
        %{f: fi, a: ai, n_games: ni} = local[team]
        put_in(local[team], %{f: fi+ff, a: ai+aa, n_games: ni+1})
      end
    end

    local
  end

  def run() do
    local = past_matches() |> init_indexes()
  end
end
我需要
local
f
a
n_游戏进行求和

local = %{
    team1: %{f: 1, a: 4, n_games: 2}
    ...
}

run()
的末尾,显然地图
local
都是0,没有更新的值。

我可以看到一些让你感到困惑的事情:

  • Enum.each/2
    将对列表中的每个项目应用一个函数,但它不会累积结果或以任何方式修改原始列表。我记不起上次使用枚举的时间了。每个枚举都有自己的位置,但非常罕见

  • 这意味着,您调用
    local[team]
    的地方实际上没有更新任何值,因为输出没有传递到任何其他地方。它本质上只是将这些变化发送到以太中

  • 解决方案:管道!我向你保证,管道操作员将改变你的生活。如果你来自OO背景,一开始有点让人难以置信,但坚持下去,我保证你永远不会想回去。帮助我思考这个问题的思维转变是,开始时尽可能少地使用匿名函数。它帮助我适应了不变性的概念,因为它迫使我思考每个函数实际需要什么值,以及如何将这些值传递给每个函数

以下是我尝试使用更以管道为中心的方法重写模块的方法——希望能有所帮助。当您在IEx中运行它时,它会产生预期的结果。如果你有任何问题,我很乐意澄清

defmodule Predictor do

  @past_matches [
    team1: %{
      team2: %{f: 0, a: 1},
      team3: %{f: 1, a: 3}
    },
    team2: %{
      team1: %{f: 3, a: 0},
      team3: %{f: 2, a: 0}
    },
    team3: %{
      team1: %{f: 1, a: 0},
      team2: %{f: 0, a: 1}
    }
  ]

  # see note 1    
  @baseline %{f: 0, a: 0, n_games: 0}

  def run(past_matches \\ @past_matches) do
    past_matches
    |> Enum.map(&build_histories/1)
    |> Enum.into(%{}) 
    # see note 2
  end

  def build_histories({team, scores}) do
    history = Enum.reduce(scores, @baseline, &build_history/2)
    {team, history}
  end

  def build_history({_vteam, vresults}, acc) do
    # see note 3
    %{acc | f: acc.f + vresults.f,
            a: acc.a + vresults.a,
            n_games: acc.n_games + 1}
  end
end

(1) since the baseline is the same for every team, you can 
    set it as a module attribute -- basically like setting a global 
    (immutable) variable that you can use as a starting point for a new 
    value. Another option would be to create a %BaseLine{} struct that 
    has default values.

(2) you could also use `Enum.reduce/2` here instead, but this does 
    effectively the same thing -- the output of the `Enum.map/1` 
    call is a list of {atom, _val} which is interpreted as a Keyword 
    list; calling `Enum.into(%{}) turns a Keyword list into a map 
    (and vice versa with `Enum.into([])`).

(3) NB:  %{map | updated_key: updated_val} only works on maps or 
    structs where the key to be updated already exists -- it'll throw 
    an error if the key isn't found on the original map.

有几件事我可以从球棒上看到,让你绊倒了:

  • Enum.each/2
    将对列表中的每个项目应用一个函数,但它不会累积结果或以任何方式修改原始列表。我记不起上次使用枚举的时间了。每个枚举都有自己的位置,但非常罕见

  • 这意味着,您调用
    local[team]
    的地方实际上没有更新任何值,因为输出没有传递到任何其他地方。它本质上只是将这些变化发送到以太中

  • 解决方案:管道!我向你保证,管道操作员将改变你的生活。如果你来自OO背景,一开始有点让人难以置信,但坚持下去,我保证你永远不会想回去。帮助我思考这个问题的思维转变是,开始时尽可能少地使用匿名函数。它帮助我适应了不变性的概念,因为它迫使我思考每个函数实际需要什么值,以及如何将这些值传递给每个函数

以下是我尝试使用更以管道为中心的方法重写模块的方法——希望能有所帮助。当您在IEx中运行它时,它会产生预期的结果。如果你有任何问题,我很乐意澄清

defmodule Predictor do

  @past_matches [
    team1: %{
      team2: %{f: 0, a: 1},
      team3: %{f: 1, a: 3}
    },
    team2: %{
      team1: %{f: 3, a: 0},
      team3: %{f: 2, a: 0}
    },
    team3: %{
      team1: %{f: 1, a: 0},
      team2: %{f: 0, a: 1}
    }
  ]

  # see note 1    
  @baseline %{f: 0, a: 0, n_games: 0}

  def run(past_matches \\ @past_matches) do
    past_matches
    |> Enum.map(&build_histories/1)
    |> Enum.into(%{}) 
    # see note 2
  end

  def build_histories({team, scores}) do
    history = Enum.reduce(scores, @baseline, &build_history/2)
    {team, history}
  end

  def build_history({_vteam, vresults}, acc) do
    # see note 3
    %{acc | f: acc.f + vresults.f,
            a: acc.a + vresults.a,
            n_games: acc.n_games + 1}
  end
end

(1) since the baseline is the same for every team, you can 
    set it as a module attribute -- basically like setting a global 
    (immutable) variable that you can use as a starting point for a new 
    value. Another option would be to create a %BaseLine{} struct that 
    has default values.

(2) you could also use `Enum.reduce/2` here instead, but this does 
    effectively the same thing -- the output of the `Enum.map/1` 
    call is a list of {atom, _val} which is interpreted as a Keyword 
    list; calling `Enum.into(%{}) turns a Keyword list into a map 
    (and vice versa with `Enum.into([])`).

(3) NB:  %{map | updated_key: updated_val} only works on maps or 
    structs where the key to be updated already exists -- it'll throw 
    an error if the key isn't found on the original map.

谢谢,这很有帮助!谢谢,这很有帮助!