Elixirで文字列の頻度を求めたいと思って調べた際の実装メモです
求めたいパタンが1通りの場合
例:関数alter_altarは入力seq
について、R
の出現頻度を求めています。
def alter_altar(_n, seq) do
r_count = Regex.scan(~r/R/, seq)
|> Enum.count
Regex.scan
については下記を参照
https://hexdocs.pm/elixir/Regex.html#scan/3
説明:
Regex.scan(~r/求めたいパタン/)
とします。
Regex.scan
を実行したままだと、マッチしたパタンを要素とするリストになっています。
例:入力WWWRRRWWWRRRRRRRW
に対して、Regex.scan(~r/R/)
を実行すると以下になります。
[["R"], ["R"], ["R"], ["R"], ["R"], ["R"], ["R"], ["R"], ["R"], ["R"]]
このため、Enum.count
で頻度を求めます。
Enum.count
については下記を参照。
https://hexdocs.pm/elixir/Enum.html#count/1
求めたいパタンが複数の場合
上記を複数パタンに拡張します。※ほぼほぼBag of Wordsです
defmodule Main do
def frequency_dist(patterns, seq) do
frequency_dist = Enum.map(patterns, fn pattern -> Regex.scan(~r/#{pattern}/, seq) end)
|> Enum.map(fn x -> Enum.count(x) end)
end
def main do
patterns = IO.read(:line) |> String.trim() |> String.split()
seq = IO.read(:line) |> String.trim()
IO.inspect frequency_dist(patterns,seq)
end
end
関数frequency_dist
は頻度を求めたい文字列パタンのリストpatterns
と対象文字列seq
の入力に対し、出現頻度のリストを返します。
例:
入力:
W R E F
WERWWWRRRRRRRRRRRRRRRR
に対して、以下の結果になります。
[4, 17, 1, 0]
補足:
同じようにパタンを求める関数として、Regex.run
があります。
https://hexdocs.pm/elixir/Regex.html#run/3
しかし、Regex.run
はマッチした最初のパタンを返します。
例:入力WWWRRRWWWRRRRRRRW
に対して、Regex.run(~r/R/)
を実行すると以下になります。
["R"]
こちらは出現頻度のカウントではなく、パタンの存在判定等に使えそうです。
サンプルは以下の問題を説いたときのものです
D - Alter Altar