Elixirを少し入門してみました。
コーディング練習がてらyukicoderのチュートリアル問題をいくつかやってみたので公開してみようと思います。
以下の問題は、初心者のためのガイドの「チュートリアルの問題を解いてみましょう!」です。
※コードの末尾にあるMain.main()
は提出する際には不要です。
No.9000 Hello World!(テスト用)
defmodule Main do
def main do
IO.puts("Hello World!")
end
end
Main.main()
$ elixir no9000_HelloWorld.exs
Hello World!
IO.puts
で出力するだけです。
No.480 合計
defmodule Main do
def main do
n = IO.gets("")
|> String.trim
|> String.to_integer
Enum.to_list(1..n)
|> Enum.reduce(&(&1 + &2))
|> IO.puts
end
end
Main.main
$ elixir no480_sum.exs
3
6
$ elixir no480_sum.exs
1
1
$ elixir no480_sum.exs
10
55
IO.gets("")
で1行取得しています。 ※この方法以外にIO.read
も使えるみたいです。
|>
はパイプライン演算子で、結果を次の処理の第1引数として渡せます(Linuxの|
と似た動き)
IO.gets("")
で取得した値には改行が含まれてしまうためString.trim
で削除しています。
String.to_integer
で数字から数値に変換しています。
Enum.to_list(1..n)
で1からnのリストを生成しています。
Enum.reduce()
でリストに対して&(&1 + &2)を適用して、リスト内の数値を合計しています。
キャプチャ演算子(&)を使用して匿名関数を省略形で記述しています。
&(&1 + &2)
とfn(a, b) -> a + b end
は同じ内容になります。
最後にIO.puts()
で出力しています。
合計するのにEnum.reduce()
を使用しましたが、Enum.sum()
を使用しても数値リストを合計できます。
No.9001 標準入出力の練習問題(テスト用)
defmodule Main do
def main do
input1 = IO.gets("")
|> String.trim
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
|> Enum.sum()
input2 = IO.gets("") |> String.trim
IO.puts("#{input1} #{input2}")
end
end
Main.main()
$ elixir no9001_inout.exs
1 2
yukicoder
3 yukicoder
IO.gets()を2回使用して2行取得しています。
1行目、取得後にString.split(" ")
でスペース区切りにリストにしています。
Enum.map
を使用して取得したリストの数字を数値に変換しています。
&String.to_integer/1
はキャプチャ演算子を使用しています。
&String.to_integer/1
と&String.to_integer(&1)
は同じです。
/1
はアリティと言い、引数の数を表しています。
Enum.sum()
で取得した数値リストを合計しています。
2行目、取得しているだけです。
IO.puts("#{} #{}")
でスペース区切りで結果を出力しています。
No.9002 FizzBuzz(テスト用)
defmodule Main do
def main do
n = IO.gets("")
|> String.trim
|> String.to_integer
Enum.to_list(1..n)
|> Enum.map(&fizzbuzz/1)
end
def fizzbuzz(n) when rem(n, 15) === 0, do: IO.puts("FizzBuzz")
def fizzbuzz(n) when rem(n, 3) === 0, do: IO.puts("Fizz")
def fizzbuzz(n) when rem(n, 5) === 0, do: IO.puts("Buzz")
def fizzbuzz(n), do: IO.puts(n)
end
Main.main()
$ elixir no9002_fizzbuzz.exs
1
1
$ elixir no9002_fizzbuzz.exs
16
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
16
取得した値をリスト化してEnum.map
を使用してリストの各数値に対して作成したfizzbuzz関数を適用しています。
関数はガード(when)を使用して値に応じて処理内容を分岐しています。
rem(n, 15)
で剰余を求めています。
No.9008 空白区切りで与えられる数値データの合計値を求める(テスト用)
defmodule Main do
def main do
_ = IO.gets("")
|> String.trim
|> String.to_integer
IO.gets("")
|> String.trim
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
|> Enum.sum()
|> IO.puts()
end
end
Main.main
$ elixir no9008_sum_numbers.exs
3
39 100 11
150
$ elixir no9008_sum_numbers.exs
10
0 1 2 3 4 5 6 7 8 9
45
$ elixir no9008_sum_numbers.exs
5
1000000 1000000 1000000 1000000 1000000
5000000
$ elixir no9008_sum_numbers.exs
2
77144313318378908 540010193228652352
617154506547031260
1行目は不要なので_
を使用して明示的に使用しないことを表しています。
2行目は取得した値をNo.9001 標準入出力の練習問題(テスト用)と同じ方法で合計して出力しています。
No.9009 改行区切りで与えられる数値データの合計値を求める(テスト用)
defmodule Main do
def main do
n = IO.gets("")
|> String.trim
|> String.to_integer
Enum.reduce(1..n, 0, fn _x, a -> sum(a) end)
|> IO.puts
end
def sum(b) do
n = IO.gets("")
|> String.trim
|> String.to_integer
b + n
end
end
Main.main
$ elixir no9009_sum_numbers.exs
3
39
100
11
150
$ elixir no9009_sum_numbers.exs
10
0
1
2
3
4
5
6
7
8
9
45
$ elixir no9009_sum_numbers.exs
5
1000000
1000000
1000000
1000000
1000000
5000000
$ elixir no9009_sum_numbers.exs
2
77144313318378908
540010193228652352
617154506547031260
ちょっとトリッキー?なやり方で合計してみました。
1行目で取得した回数Enum.reduce
を使用して入力を受け取り合計しています。
Enum.reduce
のaに順次合計していきます。
sum(a)
では受け取った値に入力された値を合計して、Enum.reduce
に戻しています。
ちょっと説明が難しい・・。
もっといいやり方があるかもですね。
No.46 はじめのn歩
defmodule Main do
def main do
[a, b] = IO.gets("")
|> String.trim
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
Float.ceil(b/a)
|> Kernel.trunc
|> IO.puts
end
end
Main.main()
$ elixir no46_first_n.exs
2 5
3
$ elixir no46_first_n.exs
10 100
10
$ elixir no46_first_n.exs
123456789 987654321
9
スペース区切りの数値をリストとして取得してパターンマッチングでa, bに入れています。
Float.ceil
でb/a
の結果を切り上げています。
Kernel.trunc
で少数を切り捨てています。
最後に出力しています。
No.388 階段(1)
defmodule Main do
def main do
[s, f] = IO.gets("")
|> String.trim
|> String.split(" ")
|> Enum.map(&String.to_integer/1)
div(s,f)
|> Kernel.trunc
|> add_one
|> IO.puts
end
def add_one(x), do: x + 1
end
Main.main()
$ elixir no388_stairs_1.exs
13 13
2
$ elixir no388_stairs_1.exs
39 10
4
$ elixir no388_stairs_1.exs
50 123
1
スペース区切りの数値をリストとして取得してパターンマッチングでs, fに入れています。
divで除算しKernel.trunc
で少数を切り捨てています。
その後、現在居る段数と一階層分の段数が同数の場合1階上にいることになるため、1足しています。
最後に出力しています。
おわり
やってみた内容は以上です。
なんとなくElixirの構文はわかってきたので、
次はPhoenixなどフレームワークを学んでみようと思います。
参考
https://qiita.com/wotsushi/items/b71c7bb5831d18246e9a
https://www.amazon.co.jp/dp/4274219151
https://elixir-lang.org/
https://elixir-lang.jp/
https://elixirschool.com/ja/