Akihito Ikeda

Elixirに1ミクロンだけ触れたので感想など

posts/2020-12-19diary

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")
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ミクロンもわからない
© Akihito Ikeda - Last update 07.04.2021 05:04.