LoginSignup
13

More than 5 years have passed since last update.

Elixir: for vs Enum vs 再帰

Last updated at Posted at 2015-11-02

概要

再帰使った方が関数型言語らしくみえるし、for よりEnumの方が最近の言語らしい。
ループをきれいに書くには?

list の要素を表示

まずは単純なもの。Enum が短い。

list
IO.puts "for"
for x <- [1, 2, 3] do
  IO.puts x
end

IO.puts "Enum"
Enum.map([1, 2, 3], &IO.puts(&1))

IO.puts "recursion"
defmodule Sample do
  def show([x|tl]) do
    IO.puts x
    show(tl)
  end

  def show([]) do
    # noop
  end
end

Sample.show [1, 2, 3]

二重ループ

2つのリストの全組み合わせを表示するループ。
for が短い。
再帰が汚い。。。

double_loop
IO.puts "for"
for x <- [1, 2, 3],
    y <- [4, 5, 6] do
  IO.inspect {x , y}
end

IO.puts "Enum"
Enum.map([1, 2, 3],
  fn x ->
    Enum.map([4, 5, 6], &IO.inspect {x, &1})
  end)

IO.puts "recursion"
defmodule Sample do
  def show([x|tl], y) do
    show(x, y)
    show(tl, y)
  end

  def show([], _) do
    # noop
  end

  def show(x, [y|tl]) do
    IO.inspect {x, y}
    show(x, tl)
  end

  def show(_, []) do
    # noop
  end
end

Sample.show [1, 2, 3], [4, 5, 6]

条件付き2重ループ

x < y となる組み合わせを表示するループ。
forは filter を使いました。
再帰はあえて guard を使ってみました。
Enum は汚く。。。

double_loop_and_conditional
IO.puts "for"
for x <- 1..3,
    y <- 1..3,
    x < y do
  IO.inspect {x , y}
end

IO.puts "Enum"
Enum.map(1..3,
  fn x ->
    Enum.map(1..3,
      fn y ->
        if x < y do
          IO.inspect {x, y}
        end
      end)
  end)

IO.puts "recursion"
defmodule Sample do
  def show([x|tl], y) do
    show(x, y)
    show(tl, y)
  end

  def show([], _) do
    # noop
  end

  def show(x, [y|tl]) when x < y do
    IO.inspect {x, y}
    show(x, tl)
  end

  def show(x, [y|tl]) do
    show(x, tl)
  end

  def show(_, []) do
    # noop
  end
end

Sample.show Enum.to_list(1..3), Enum.to_list(1..3)

最後に

for 最強!

ではなく、あきらかに経験不足だと思います。
パイプとか高階関数とか使うと綺麗に書けるのかもしれません。

Enum 的なもので次のように書けるものを作るといいのかもしれません。

ExEnum
ExEnum.map([1,2,3], [1,2,3], &IO.inspect({&1, &2})
ExEnum.map([[1,2,3], [1,2,3]], &IO.inspect({&1, &2})

また、当然状況によって使い分ける必要もあると思います。
経験積んで良い書き方が分かってきたら更新します。

追記

@antimon2 さんに 順列組合せの関数を使った回答例 を書いていただけました。
順列組合せの関数があればさくっと書けるレベルだと思いますが、順列組合せの関数から作っていただいているので、すごく勉強になります。
最後のは組合せを狙ったわけではなかったのですが、条件を見て簡潔な関数を選ぶところも参考になりました。

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
13