Elixirに1ミクロンだけ触れたので感想など
Elixirのこと1ミクロンも知らないけど、ひとまず1ミクロンでも何かやってみるかと思い定番のAtCoder精選過去問10問をやってみた。以下はメモとか感想とか気づいたことなど。
IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
a b c d
みたいな入力を読む定型的なやつ
def main do
solve(x) |> IO.puts()
end
IO.puts()
し忘れる(1WAくらった)
def solve(a, b) when rem(a * b, 2) == 0, do: "Even"
def solve(_, _), do: "Odd"
- whenでガードが書ける
iex(2)> String.codepoints("abcde")
["a", "b", "c", "d", "e"]
iex(3)> String.codepoints("ゴッドブレスの導きぃ〜")
["ゴ", "ッ", "ド", "ブ", "レ", "ス", "の", "導", "き", "ぃ", "〜"]
- 文字列を1文字ずつにしてくれる
iex(5)> rem(10, 2)
0
iex(6)> rem(10, 3)
1
%
演算子ない →rem()
を使う
iex(8)> 10 / 3
3.3333333333333335
iex(9)> div(10, 3)
3
- 整数同士の割り算でも少数になる
div
を使えば整数になる
iex(7)> recompile
Compiling 1 file (.ex)
Generated at_coder app
- iexで
recompile
して新しく追加したモジュールを読み込む
iex(22)> an = [2, 4, 6]
[2, 4, 6]
iex(23)> Enum.all?(an, &rem(&1, 2) == 0)
true
iex(24)> an = [1, 2, 4]
[1, 2, 4]
iex(25)> Enum.all?(an, &rem(&1, 2) == 0)
false
all?
がある&rem(&1, 2)
こうやって書けるのもいい
Enum.map(an, &div(&1, 2)) |> solve(acc + 1)
def solve(an, acc) do
...
- パイプライン演算子の役割が、前の式の結果を次の式の1つ目の引数として渡すことらしい
solve/2
を繋げられる
for(i <- 0..a, j <- 0..b, k <- 0..c, 500 * i + 100 * j + 50 * k == x, do: {i, j, k})
|> Enum.count()
- forがこんな感じでかける(for文というよりはリスト内包表記)
Enum.sort(an) |> Enum.map_every(2, &(-&1)) |> Enum.sum() |> abs
&(-&1)
はEnum.map_every(2, fn(n) -> n * -1 end)
と同じ意味map_every/3
便利(nthおきにfunを適用)
for(_ <- 1..n, do: IO.read(:line) |> String.trim() |> String.to_integer())
|> solve()
|> IO.puts()
- n行の入力があるときのやつ
MapSet.new(list)
- set
|> Enum.at(0, "-1 -1 -1")
- https://hexdocs.pm/elixir/Enum.html#at/3
at(enumerable, index, default \\ nil)
- Returns default if index is out of bounds.
iex(121)> ~w(dream dreamer erase eraser)
["dream", "dreamer", "erase", "eraser"]
- ちゃんとこういうのもある
Enum.reduce_while(nil, fn(word, acc) ->
if String.starts_with?(s, word) do
{:halt, String.slice(s, String.length(word)..-1)}
else
{:cont, acc}
end
end)
:halt
,:cont
でリダクションを停止・継続できる- カンマのあとでaccumulatorを更新できる
iex(124)> 1..n |> Enum.reduce([], fn _, acc ->
...(124)> list = IO.read(:line) |> String.trim() |> String.split(" ") |> Enum.map(&String.to_integer/1)
...(124)> [list | acc]
...(124)> end)
1 2 3
4 5 6
[[4, 5, 6], [1, 2, 3]]
- 複数行の入力を2次元配列で読み取るやつ
iex(127)> an = [1, 2, 3]
[1, 2, 3]
iex(128)> bn = [4, 5, 6]
[4, 5, 6]
iex(129)> [an | bn]
[[1, 2, 3], 4, 5, 6]
- ただ単に
[an | bn]
とすると[[1, 2, 3], 4, 5, 6]
になる - 一つ前のコードではreduceで畳み込んでるから綺麗な2次元配列になる
- (つまりこうなってる↓)
iex(131)> [bn | [an | []]]
[[4, 5, 6], [1, 2, 3]]
- 当然だが右端の
[]
はaccumulatorの初期値
全体として
- 書いてて楽しい感じがする(逆に楽しくないのって何よって感じだけど)
|>
をタイプするのが結構めんどう-
再帰脳にスイッチするのが結構大変だった
- acc(accumulator)という変数名がなかなか出てこずcntとかresとか書いてた
-
リダクション脳に(ry
redule_while
をよく使いそう
- パターンマッチが全然使えてない
- Elixir、1ミクロンもわからない