この記事は、Elixir Advent Calendar 2024 シリーズ9 の10日目です
【本コラムは、3分で読め、3分で試せます】
piacere です、ご覧いただいてありがとございます
Enum.frequencies は、Elixir 1.10で追加された、リスト中の値の発生頻度を数えてくれる便利な関数で、利用頻度もそれなりに高いのですが、Elixir 1.9までは存在していなかったので、自前で作る必要があったので、作り方を解説します
Enum.frequencies(["abc", "abc", "xyz", "abc", "def", "xyz"])
%{"abc" => 3, "def" => 1, "xyz" => 2}
Enum.frequencies([
%{"a" => "abc"},
%{"b" => "abc"},
%{"a" => "xyz"},
%{"a" => "abc"},
%{"a" => "def"},
%{"a" => "xyz"}
])
%{
%{"a" => "abc"} => 2,
%{"a" => "def"} => 1,
%{"a" => "xyz"} => 2,
%{"b" => "abc"} => 1
}
そんな集計処理を叶えてくれるパーツが、これまた便利な Map.update です
単品のMap.updateは、第1引数にあるマップに対し、第2引数のキーで、第3引数の初期値と第4引数の関数で計算した値をマップに追加してくれます
Map.update(%{}, "a", 1, fn x -> x + 1 end)
%{"a" => 1}
この特性を、パイプで使うと、下記のようなマップの更新処理が実現できます
%{}
|> Map.update("a", 1, fn x -> x + 1 end)
|> Map.update("b", 1, fn x -> x + 1 end)
|> Map.update("a", 1, fn x -> x + 1 end)
%{"a" => 2, "b" => 1}
同じようなことをEnum.reduceで行うと、リストに対する集計を行い、集計結果をマップとして残すことが可能です
datas = ["abc", "abc", "xyz", "abc", "def", "xyz"]
datas
|> Enum.reduce(%{}, & Map.update(&2, &1, 1, fn x -> x + 1 end))
%{"abc" => 3, "def" => 1, "xyz" => 2}
こうしたEnum.reduceによる集計処理が自由に書けるようになると、Elixirをはじめとする関数型言語に対する「苦手意識」のようなものが無くなり、関数型言語以外を触りたいとは思えなくなるので、ぜひマスターしてみてください