defmodule FightingSpirit do
def shout do
IO.puts "元氣ですかーーーッ!!!"
IO.puts "元氣があればなんでもできる!"
IO.puts "闘魂とは己に打ち克つこと。"
IO.puts "そして闘いを通じて己の魂を磨いていく"
IO.puts "ことだと思います。"
end
end
FightingSpirit.shout()
$\huge{元氣ですかーーーッ!!!}$
$\huge{元氣があればなんでもできる!}$
$\huge{闘魂とは己に打ち克つこと。}$
$\huge{そして闘いを通じて己の魂を磨いていく}$
$\huge{ことだと思います。}$
はじめに
ElixirのEnumモジュールは、リストやマップなどのコレクションを扱う際に非常に便利です。本記事では、日常のプログラムで役立つEnum.map/2, Enum.filter/2, Enum.reduce/3の3つの関数を例を交えながら解説します。それぞれの関数はElixirのコードをシンプルかつ効率的に書くために欠かせない存在です。
独断と偏見ですがよく使います!
1. Enum.map/2
でリストの要素を変換する
Enum.map/2
はリスト内の各要素を順番に処理し、新しいリストを生成する関数です。使い方は、変換したいリストと処理を行う無名関数を渡すだけです。
例: 値を2倍にする
以下のコードはリスト内の値を2倍に変換します。
list = [1, 2, 3, 4]
new_list = Enum.map(list, fn x -> x * 2 end)
実行結果
実行結果は次のようになります。
[2, 4, 6, 8]
解説
Enum.map/2
は、リストの要素ごとに無名関数fn x -> x * 2 end
を適用し、新しいリストを返しています。このように簡潔に変換処理を行えるため、データの加工に便利です。
ちなみに無名関数は& &1 * 2
とも書けます。この書き方もよく見かけるので覚えておくとよいでしょう。
2. Enum.filter/2
で条件に合う要素を選択する
Enum.filter/2
は、リストの要素の中から指定した条件に合う要素だけを抽出する関数です。リストとフィルターを行う無名関数を渡すと、新しいリストが返ってきます。
例: 偶数だけを抽出する
以下のコードは、リストの中から偶数のみを抽出します。
list = [1, 2, 3, 4, 5, 6]
even_list = Enum.filter(list, fn x -> rem(x, 2) == 0 end)
実行結果
実行結果は次のようになります。
[2, 4, 6]
解説
Enum.filter/2
は、各要素を無名関数fn x -> rem(x, 2) == 0 end
で偶数かどうかを確認し、条件を満たす(つまり偶数である)要素だけをリストに残しています。条件に合うデータだけを取り出したいときに非常に便利です。
3. Enum.reduce/3
でリストを畳み込む
Enum.reduce/3はElixirの最初の鬼門です。専門家の間では畳み込みと呼ばれます。
Enum.reduce/3
は、リストの全ての要素を他の表現へ畳み込む関数です。これまでみてきたEnum.map/2
とEnum.filter/2
はリストが得られていました。それに対してEnum.reduce/3
は、初期値と処理を行う関数を渡すことで、他の型のデータを作ることができます。
例: リスト内の要素の出現回数を数える
以下のコードでは、リスト内の要素(アトム)の出現回数を数えてマップを返しています。
list = [:inoki, :baba, :inoki, :baba, :inoki]
Enum.reduce(list, %{}, fn e, acc -> Map.update(acc, e, 1, & &1 + 1) end)
実行結果
実行結果は次のようになります。
%{inoki: 3, baba: 2}
解説
ここでは、Enum.reduce/3
に初期値として空のマップ%{}
と無名関数fn e, acc -> Map.update(acc, e, 1, & &1 + 1)
を渡し、リスト内の要素を次々と数えています。
無名関数の第1引数e
はリストの要素です。第2引数のacc
はアキュムレータと呼ばれるもので直前までの無名関数の評価結果です。最初は初期値の空のマップ%{}
が入っています。具体的には以下のように更新されていきます。
Index | e | acc | 評価結果 |
---|---|---|---|
0 | :inoki |
%{} |
%{inoki: 1} |
1 | :baba |
%{inoki: 1} |
%{inoki: 1, baba: 1} |
2 | :inoki |
%{inoki: 1, baba: 1} |
%{inoki: 2, baba: 1} |
3 | :baba |
%{inoki: 2, baba: 1} |
%{inoki: 2, baba: 2} |
4 | :inoki |
%{inoki: 2, baba: 2} |
%{inoki: 3, baba: 2} |
Enum.reduce/3は、集約処理や合計計算などに役立つ関数です。
ちなみにこの例と同じことは、Enum.frequencies/1一発でできることを付記しておきます。
どうやって実行するんだー!? バカヤローって方へ
GitHubのアカウントをお持ちの方へお手軽な方法を示しておきます。
PhoenixアプリケーションをGitHub Codespaces上で開発する方法で紹介したGitHub Codespacesを使うという方法です。
記事中で紹介しているphx_devcontainerを使うと、ElixirがインストールされたUbuntuコンテナが立ち上がるので、Ubuntu上で直接開発をしているかのように操作ができます。iex
コマンドでREPL(Read-Eval-Print Loop)が立ち上がるのでこの記事のコード例をぜひ試してください。
まとめ
ElixirのEnum
モジュールには、データ操作をシンプルにしてくれる便利な関数が揃っています。今回紹介したEnum.map/2
, Enum.filter/2
, Enum.reduce/3
は特に日常的によく使うデータ処理や変換に不可欠な存在です。
一手一手に闘魂を込めて、シンプルで力強いコードを書いていきましょう!