はじめに
- @nasu_onigiri さんの2次元配列の動きを眺める関数を作った(Python)を拝見しまして、私はElixirでやってみようとおもいました
0. 準備
$ mix new list_of_lists
$ cd list_of_lists
1. ソースコードを書く
- はい、ドン
lib/list_of_lists.ex
defmodule ListOfLists do
@n 3
@m 3
@timeout 1000
def main do
[head | tail] = results()
print({head, {nil, nil}})
Process.sleep(@timeout)
Enum.zip(tail, for(i <- 0..(@n - 1), j <- 0..(@m - 1), do: {i, j}))
|> Enum.zip(List.duplicate(@timeout, @n * @m))
|> Enum.flat_map(fn {a, b} -> [a, b] end)
|> Enum.each(&print/1)
Enum.at(tail, -1) |> to_s(@n - 1, @m - 1, false) |> IO.puts()
end
defp results do
for(i <- 0..(@n - 1), j <- 0..(@m - 1), do: {i, j})
|> Enum.reduce([init_list_of_lists(@n, @m)], fn {i, j}, acc ->
last =
Enum.at(acc, -1)
|> get_and_update_in([Access.at(i), Access.at(j)], &{&1, pow(3, i + j)})
|> elem(1)
acc ++ [last]
end)
end
defp init_list_of_lists(n, m) do
1..n |> Enum.map(fn _ -> List.duplicate(0, m) end)
end
defp print(n) when is_integer(n), do: Process.sleep(n)
defp print({list_of_lists, {i, j}}) do
to_s(list_of_lists, i, j)
|> IO.puts()
end
defp to_s(list_of_lists, i, j, move \\ true, count \\ 5) do
for(k <- 0..(@n - 1), l <- 0..(@m - 1), do: {k, l})
|> Enum.map(fn {k, l} ->
value_with_leading =
get_in(list_of_lists, [Access.at(k), Access.at(l)])
|> Integer.to_string()
|> String.pad_leading(count)
if k == i && l == j do
"\x1b[31m#{value_with_leading}\x1b[0m"
else
value_with_leading
end
end)
|> Enum.chunk_every(@m)
|> Enum.map(&Enum.join/1)
|> Enum.join("\n")
|> (fn s -> "(#{i}, #{j})\n" <> s end).()
|> (fn s -> if(move, do: s <> "\x1b[#{@n + 1}A", else: s) end).()
end
defp pow(_, 0), do: 1
defp pow(n, m), do: n * pow(n, m - 1)
end
- 二次元リストの更新には、Kernel.get_and_update_in/3を使いました
- こんな便利な関数をはじめて使ってみました
- お仲間には次のようなものがあります
- Kernel.get_in/2
- Kernel.put_in/3
- リンク先のサンプルをみていただくとどんなものかご理解いただけるとおもいます
-
Designing Elixir Systems With OTP: Write Highly Scalable, Self-Healing Software With Layersという買ってからほとんど読めていない本にそういえば
○、✗
ゲームのデータ構造の説明で便利そうな関数を使っていたことを思い出してひっぱりだしてきてから思い出しました -
list_of_lists
という言い方は、List.zip/1の引数名で使われていて、リストの各要素がリストである場合のネイティブな言い方なのだろうと思っています
- こんな便利な関数をはじめて使ってみました
- Python版の元記事で
'\033'
つまりESC
はElixirでは"\0x1b"
と書きます- Escape charactersで知りました
2. 実行する
$ iex -S mix
iex> ListOfLists.main