LoginSignup
7
3

More than 5 years have passed since last update.

Elixir: 列挙型データから値を探すEnumモジュールの関数

Last updated at Posted at 2019-01-30

Enumは列挙型(enumerable)データを扱うモジュールです。Enumの関数はさまざまな列挙可能なデータ型に使える多態性をもちます。扱うデータはEnumerableプロトコルを実装していればよいのです(「Elixir入門 10: EnumとStream」参照)。それらの関数の中から、値を探す3つの関数をご紹介します。とくに、Enum.find_value/3については、公式ドキュメントよりわかりやすいコード例を示しました。

Enum.find/3

Enum.find/3は、第3引数funの戻り値がtrueと評価される最初の要素を返します。関数が引数に受け取るのは、取り出される各要素です。

find(enumerable, default \\ nil, fun)
find(t(), default(), (element() -> any())) :: element() | default()

第2引数はデフォルト値です。省くとnilが与えられます。

iex> Enum.find([1, 2, 3], fn x -> rem(x, 2) == 0 end)
2
iex> Enum.find([1, 2, 3], fn x -> rem(x, 4) == 0 end)
nil
iex> Enum.find([1, 2, 3], 0,  fn x -> rem(x, 4) == 0 end)
0

Enum.find_index/2

Enum.find_index/2は、第2引数funの戻り値がtrueと評価される最初の要素のインデックスを返します。関数が引数に受け取るのは、取り出される各要素です。

find_index(enumerable, fun)
find_index(t(), (element() -> any())) :: non_neg_integer() | nil

インデックスは0から始まる連番整数です。いずれの要素も、第2引数の関数funtrueと評価される値を返さないときはnilとなります。

iex> Enum.find_index([1, 2, 3], fn x -> rem(x, 2) == 0 end)
1
iex> Enum.find_index([1, 2, 3], fn x -> rem(x, 4) == 0 end)
nil

Enum.find_value/3

Enum.find_value/3は、第3引数funの戻り値がtrueと評価される最初の要素について、戻り値そのものを返します。関数が引数に受け取るのは、取り出される各要素です。

find_value(enumerable, default \\ nil, fun)
find_value(t(), any(), (element() -> any())) :: any() | nil

第2引数はデフォルト値です。省くとnilが与えられます。

iex> Enum.find_value([1, 2, 3], fn x -> rem(x, 2) == 0 end)
true
iex> Enum.find_value([1, 2, 3], fn x -> rem(x, 4) == 0 end)
nil
iex> Enum.find_value([1, 2, 3], &is_number/1)
true
iex> Enum.find_value([1, 2, 3], "no bools!", &is_boolean/1)
"no bools!"
iex> Enum.find_value([1, 2, 3], fn x ->
...>   case rem(x, 2) do
...>     0 -> {:even, x}
...>     _ -> false
...>   end
...> end)
{:even, 2}

公式ドキュメントのEnum.find_value/3の項には、使い途の浮かぶ例が掲げられていないようです。たとえば、つぎのようにキーワードリストから値を取り出すことが考えられます。

iex> profile = [{company: "gumi, inc"}, {headquarters: "tokyo/japan"}]
iex> Enum.find_value(profile, fn {key, value} ->
...>   case key do
...>     :headquarters -> value
...>     _ -> false
...>   end
...> end)
"tokyo/japan"

この例は、and/2を用いるともっと短く書けます。

iex> Enum.find_value(profile, fn {key, value} -> key == :headquarters and value end)
"tokyo/japan"
7
3
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
7
3