トヨタシステムズプログラミングコンテスト2023(AtCoder Beginner Contest 330)の A - Counting Passes を Elixir で解きましたので,ご報告します.
問題
簡易ローカルテスト環境の構築
次のようなMakefileを書きました.
.phony: all clean
test: test_ex
test_ex:
elixir test.exs < in1.txt | diff - out1.txt
elixir test.exs < in2.txt | diff - out2.txt
elixir test.exs < in3.txt | diff - out3.txt
Code.eval_file("main.exs")
Main.main()
入力例1をin1.txt,出力例1をout1.txtのように与え,main.exsに解答を書きます.その後,makeコマンドを実行します.
解答例
defmodule Main do
def main() do
[_n, l] = read_int_list()
a = read_int_list()
a
|> Enum.filter(& &1 >= l)
|> Enum.count()
|> IO.puts()
end
def read_int_list() do
IO.read(:line)
|> String.trim()
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
end
end
関数Main.read_int_list/0は,IO.read/2で標準入力から1行読み取り,String.trim/1で改行文字を取り除いた後,String.split/3で空白文字で区切ってリストにしてから,Enum.map/2で各要素について,String.to_integer/1を適用して文字列を数字に変換し,その結果のリストを返します.
これにより,まず,nとlを読み込みます.nは使用しないので,_nと書くことで,nを読み捨てます.
次にリストaを読み込みます.その後,aをEnum.filter/2でl以上の値を持つ要素を抽出し,Enum.count/1で個数を数えます.最後に結果をIO.puts/2で出力します.
別解
aを使わずに,パイプラインで直接繋ぐこともできます.
defmodule Main do
def main() do
[_n, l] = read_int_list()
read_int_list()
|> Enum.filter(& &1 >= l)
|> Enum.count()
|> IO.puts()
end
def read_int_list() do
IO.read(:line)
|> String.trim()
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
end
end
さらにEnum.count/2を使って,Enum.filter/2とEnum.count/1を合わせてしまいます.
defmodule Main do
def main() do
[_n, l] = read_int_list()
read_int_list()
|> Enum.count(& &1 >= l)
|> IO.puts()
end
def read_int_list() do
IO.read(:line)
|> String.trim()
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
end
end
実行時間やメモリ使用量はともかくとして,Elixirはデータ変換パラダイムによって,書きたいことをストレートに,かつ簡潔に書けますね.