追記:20170702
Enum.random/1を使ふのが好い。
Enum – Elixir v1.4.5
Rubyだと
xs.sample
である。JavaScriptだと
xs[Math.floor(Math.random() * xs.length)];
となる。Elixirでもこれに近いことを行ふ。Erlangのrandomモジュールを使ってみると
Enum.at(xs, :random.uniform(Enum.count xs) - 1)
となる。これでよささうに見える。しかし何回か試してみるとわかるが、randomの乱数列はシードが一定なのだ。手動でシードしてやらなければやらない。
:random.seed :os.timestamp IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1) IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1) IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1) :random.seed :os.timestamp IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1) IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1) IO.inspect Enum.at(xs, :random.uniform(Enum.count xs) - 1)
これでよささうに見える。だがこのシードはプロセスごとに独立してゐるのだ。つまりプロセスを作るたびにプロセスの中でシードしてやらねばならない。しかもこれだとミリ秒の精度だから、プロセスを高速に大量につくるErlang (Elixir) では、頻繁にシードがかぶってしまふ。困る。
そこでrandomの代はりにcryptoモジュールを使ってみる。
Enum.at xs, rem(:crypto.bytes_to_integer(:crypto.rand_bytes 1), Enum.count xs)
重さうだが以上の欠点はない。cryptoの値でrandomをシードしてやるのもよいとおもふ。