LoginSignup
1
1

More than 5 years have passed since last update.

ElixirのComprehensions(内包表記)

Last updated at Posted at 2014-08-30

Comprehensions(内包表記)の使い方

ElixirのComprehensionsは

  • Generators
  • Filters
  • Collectables

の3つで構成されている。

> for n <- [1, 2, 3, 4], do: n * n
[1, 4, 9, 16]

上記の場合、n <- [1, 2, 3, 4]Generatorsになる。右辺に任意のenumerableを渡すことが可能。

例えば、

> for n <- 1..4, do: n * n
[1, 4, 9, 16]

とすることも出来る。
また、Generatorsはパターンマッチングもサポートしているので、

> values = [good: 1, good: 2, bad: 3, good: 4]
> for {:good, n} <- values, do: n * n
[1, 4, 16]

のように書ける。
パターンマッチングではなく、Filtersを使って同等の事が出来る。

> values = [good: 1, good: 2, bad: 3, good: 4]
> for {key, n} <- values, key == :good, do: n * n
[1, 4, 16]

> require Integer
> for n <- 1..4,Integer.is_odd(n), do: n * n
[1, 9]

Filtersは、nilまたはfalseの値を除外対象とする。

> require Integer
> for n <- 1..4, nil, do: n * n
[]

以下の様に複数のGeneratorsを指定出来る。

> for dir <- ['.'],
>     file <- File.ls!(dir),
>     path = Path.join(dir, file),
>     File.regular?(path) do
>   path
> end
["./.gitignore", "./mix.exs", "./README.md"]

Bitstringも同様に扱える。

> pixels = <<213, 45, 132, 64, 76, 32, 76, 0, 0, 234, 32, 15>>
> for <<r::8, g::8, b::8 <- pixels>>, do: {r, g, b}
[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]

パターンマッチングもFilters使える。

> for <<r::8, g::8, b::8 <- pixels>>, r==213, do: {r, g, b}
[{213, 45, 132}]
> for <<213::8, g::8, b::8 <- pixels>>, do: {213, g, b}
[{213, 45, 132}]

Intoの使い方

上記の、Comprehensions(内包表記)は、結果をリストとして返しているが、
:intoを使用すと、異なるデータ構造にデータを登録する事が可能。

> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

:intoにはCollectable protocolを実装しているデータ構造であれば指定が可能。
1.0.0-rc2では、List / BitString / Map / HashDict / HashSet / IO(IO.Stream)が実装済

List

> box = [100,200]
> for n <- [1,2,3,4,5], into: box, do: n + 1
[100, 200, 2, 3, 4, 5, 6]

BitString

> for <<c <- " hello world ">>, c != ?\s, into: "", do: <<c>>
"helloworld"

Map

> for {key,value} <- [app: "elixir", version: "0.15.2-dev"],
>     into: %{} do
>   {key, value: value}
> end
%{app: [value: "elixir"], version: [value: "0.15.2-dev"]}

%{}Map.newにも置き換え可能。

MapはDictモジュールに処理を委譲しているだけなので、HashDict/HashSetも同じように記述出来る。
%{}の部分がHashDict.newまたはHashSet.newになる。

IO.Stream

> stream = IO.stream(:stdio, :line)
> for line <- stream, into: stream do
>   String.upcase(line) <> "\n"
> end

> for x <- ~w{ cat dog }, into: IO.stream(:stdio,:line), do: "<<#{x}>>\n"

参考

1
1
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
1
1