首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于另一个嵌套Map迭代的更新地图

基于另一个嵌套Map迭代的更新地图
EN

Stack Overflow用户
提问于 2017-06-04 22:32:53
回答 1查看 484关注 0票数 0

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

代码语言:javascript
运行
复制
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

我需要localfan_games相加。

代码语言:javascript
运行
复制
local = %{
    team1: %{f: 1, a: 4, n_games: 2}
    ...
}

显然,在run()的末尾,Map local具有所有的0's值,并且没有更新的值。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2017-06-05 00:37:41

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

  • Enum.each/2将对列表中的每个项应用一个函数,但它不会以任何方式累积结果或修改原始列表。我不记得我最后一次使用Enum.each是什么时候--它有它的位置,但它非常罕见。
  • 这意味着调用local[team]的地方实际上没有更新任何值,因为输出没有传递到其他任何地方。从本质上说,这只是将这些变化转化为以太。
  • 解决办法:管道!我向你保证|>管道工会改变你的生活。如果你是一个OO背景,但坚持下去,我保证你再也不想回去了。让我头脑清醒的是,最初尽可能少地使用匿名函数是思想上的转变。它帮助我适应了不变的概念,因为它迫使我思考每个函数实际需要什么值,以及如何将这些值传递给每个函数。

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

代码语言:javascript
运行
复制
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.
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44359447

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档