【问题标题】:Return Map or Convert to Map? word-count elixir返回地图还是转换为地图?字数灵丹妙药
【发布时间】:2020-08-06 17:01:41
【问题描述】:

解决 Elixir 中的练习字数问题。目标是返回一个包含句子中每个单词的字数的映射。即如果字符串“一条鱼两条鱼红鱼蓝鱼”是输入输出应该是%{ "one" => 1 , "fish" => 4 , "two" => 1 , "red" => 1 , "blue" => 1 }

据我所知:

iex(14)> sentence = "one fish two fish red fish blue fish"
"one fish two fish red fish blue fish"
iex(15)> String.split(sentence)                                                                         
["one", "fish", "two", "fish", "red", "fish", "blue", "fish"]
iex(16)> String.split(sentence) |> Enum.group_by(fn(x) -> x end)
%{"blue" => ["blue"], "fish" => ["fish", "fish", "fish", "fish"],
  "one" => ["one"], "red" => ["red"], "two" => ["two"]}

如何迭代此映射并在值上运行 Enum.count?我试过Enum.map(fn {k, v} -> {k, Enum.count(v)} end),但它返回一个元组列表[{"blue", 1}, {"fish", 4}, {"one", 1}, {"red", 1}, {"two", 1}]。我需要将元组转换为映射还是有更好的方法?如果我需要将元组转换为地图类型,我该怎么做?

我是 Elixir 和 Erlang 的新手,所以如果有人能告诉我为什么当你将映射传递给 Enum.map 函数时,你会得到一个元组列表而不是一个有用的映射。

【问题讨论】:

    标签: elixir


    【解决方案1】:

    您可以使用 Enum.into/2 转换对列表(具有 2 个元素的元组):

    [{"blue", 1}, {"fish", 4}, {"one", 1}, {"red", 1}, {"two", 1}] |> Enum.into(%{})
    

    您可以将Enum.reduce/3 改为新地图以防止额外的枚举:

    String.split(sentence)
    |> Enum.group_by(fn(x) -> x end)
    |> Enum.reduce(%{}, fn {k, v}, acc -> Map.put(acc, k, Enum.count(v)) end)
    

    在 Enumerable 协议的实现中,地图被显式转换为对列表:https://github.com/elixir-lang/elixir/blob/v1.1.1/lib/elixir/lib/enum.ex#L2619

    您也可以使用 Enum.reduce 和 Map.update/4 一次性计算列表中的单词:

    String.split(sentence)
    |> Enum.reduce(%{}, fn word, acc -> Map.update(acc, word, 1, &(&1 + 1)) end)
    

    【讨论】:

    • 是的,这行得通。你能帮我理解 Map.update 是如何工作的吗?所有的输入是什么? &是什么?
    • 我链接的文档中解释了输入。您可以在 elixir-lang.org/docs/stable/elixir/… 阅读 &() 的文档。 &(&1 + 1)fn x -> x + 1 end 相同
    • 好的,谢谢。我相信我现在明白了。您提供的最后一个选项更短,但由于幻数,它读起来不太好。我和我的工作重视可读性而不是聪明,所以我的投票是group_by,然后是reduce 选项。只是为了确认一下,Map.update 中的第一个 1 是初始值或默认值,第二个 1 根本不是 1(它是 map 中键值对的当前值),第三个 1 是增量值如果密钥存在,则为 1。对吗?
    • 你是对的。如果映射中不存在键,则第一个参数 (1) 是初始值。 ``&(&1 + 1)` 是一个将当前值 (&1) 增加 1 的函数。
    【解决方案2】:

    注意:使用elixir-1.10,您可以利用Enum.frequencies 功能。

    "one fish two fish red fish blue fish" 
    |> String.split(" ")
    |> Enum.frequencies
    

    这样你就可以用 pipe-operator 做这一切了?

    【讨论】:

      猜你喜欢
      • 2018-06-12
      • 2019-02-15
      • 2018-10-11
      • 1970-01-01
      • 2019-11-30
      • 1970-01-01
      • 2010-10-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多