LoginSignup
8
7

More than 5 years have passed since last update.

ElixirのEnumerablesとStreams

Last updated at Posted at 2014-08-31

2015/08/06のmaster(v1.1.0-dev)で動作確認

Enumerables

Enumモジュールを使う。

> Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
> Enum.map(%{1 => 2, 3 => 4}, fn {k, v} -> k * v end)
[2, 12]

> Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
> Enum.reduce(1..3, 0, &+/2)
6

ドキュメント参照

少し調べた感じでは、

  • List
  • Map
  • Function
  • GenEvent.Stream
  • HashDict
  • HashSet
  • Range
  • Stream

Protocolsを使ってEnumerableを実装している。

Enumerables -> Streams

Enumモジュールの殆どの関数はEnumerableを引数にとり、戻り値はlistを期待している。

> odd? = &(rem(&1, 2) != 0)
#Function<6.90072148/1 in :erl_eval.expr/5>
> Enum.filter(1..3, odd?)
[1, 3]

上記は、中間リストを生成している。

> 1..100_000 |> Enum.map(&(&1 * 3)) |> Enum.filter(odd?) |> Enum.sum
7500000000

上記の場合は、100_000のリストをEnum.mapに渡し、3倍したあと、Enum.filterで奇数のみ取得して、最後にEnum.sumを行っている。
Lazy operationsをサポートしているStreamモジュールを使うと以下のように書ける。

> 1..100_000 |> Stream.map(&(&1 * 3)) |> Stream.filter(odd?) |> Enum.sum
7500000000

上記は中間リストを生成する代わりに、ストリームを生成する。
毎回リストを作る事をしないので大量のデータを扱う場合、または無限な値を扱うのに適している。
実際にEnum.map/Enum.filterStream.map/Stream.filterに変えてみたけど、劇的には変わらなかった。
例が悪いのかな??
と思ったけど、以下の場合は処理速度が全然違う。一つ目が 20秒 二つ目が 0.00008秒

> Enum.map(1..10_000_000, &(&1+1)) |> Enum.take(5)
[2, 3, 4, 5, 6]
> Stream.map(1..10_000_000, &(&1+1)) |> Enum.take(5)
[2, 3, 4, 5, 6]
  • Streamモジュールの殆どは、enumerableを引数のとり、streamデータ型を返す関数となっている。
  • Streamモジュールは無限値(streamデータ型)を得る事が出来る関数が備わっている。

    • 例) Stream.cycle/1で得られるstreamをEnum.mapに渡すと無限ループする。

      > stream = Stream.cycle([1, 2, 3])
      #Function<44.83110278/2 in Stream.unfold/2>
      > Enum.take(stream, 10)
      [1, 2, 3, 1, 2, 3, 1, 2, 3, 1]
      > Enum.map stream, fn(x) -> x * x end
      結果が返ってこない。
      

あとは、

  • Stream.unfold/2
  • Stream.resource/3

など、色々な関数が存在する。使い方はドキュメントを見た方が早い。
あとは

iex> h Stream.unfold

とかで調べる。あーでも@specの情報が無いからドキュメント見た方がいいか。

他の使い方

> Stream.map([1, 3, 5, 7], &(&1 + 1)) |> Enum.to_list
[2, 4, 6, 8]

参考

8
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
7