shuhelohelo’s blog

Xamarin.Forms多めです.

ElixirのEnumとLinqの共通点

@zacky1972さんのTweetをみて、EnumってLinqに似ているなと思ったのでElixirの勉強がてらLinqとElixirの両方で書いてみたりしました。

Enum.reduceとIEnumerable.Aggregation

畳み込みです。 累積値(デフォルトでは1)と要素(先頭から順に)をとって関数を実行し、それを累積値とし、次の要素を取り出して関数を実行…を繰り返すものです。 これはどちらも結果は6になります。

Enum.reduce([1,2,3],fn x,acc->x+acc end)
(new[] { 1, 2, 3 }).Aggregate((x, acc) => x + acc);

どういう計算かというとこんな計算です。 累積値の初期値はデフォルトでは0です。

            int acc = 0;
            foreach (var x in (new[] { 1, 2, 3 }))
            {
                acc = acc + x;
            }

では累積値の初期値を指定しましょう。 初期値を1にします。 結果はどちらも7です。

Enum.reduce([1, 2, 3], 1, fn x, acc -> x + acc end)
(new[] { 1, 2, 3 }).Aggregate(1, (x, acc) => x + acc);

つまりこんな計算です。

int acc = 1;
foreach (var x in (new[] { 1, 2, 3 }))
{
    acc = acc + x;
}

では以下の計算をElixirとLinqのそれぞれで書いてみましょう。

1*1*2*3*4=24
Enum.reduce([1,2,3,4],1,fn x,acc -> x * acc end)
(new[] { 1, 2, 3, 4 }).Aggregate(1, (x, acc) => x * acc);

Enum.map/2とEnum.reduce/3を使って[1,2,3]の各要素を2倍して総和を求めるプログラムを書いてみる

Enum.mapLinqだとSelectですね。 もとの配列から新しい配列を作るときに使います。 今回の例で言えば「各要素を2倍して」の部分に使います。

 [1,2,3]
 |>Enum.map(fn x->x*2 end)
 |>Enum.reduce(fn x,acc->x+acc end)
(new[] { 1, 2, 3 })
    .Select(x => x * 2)
    .Aggregate((x, acc) => x + acc);

結果は12です。

次は[1,2,3]の各要素を2倍して、更に各要素に1加えてから総和を求める、です。 先程と比較すると、mapもしくはSelectが一段増えました。

 [1,2,3]
 |>Enum.map(fn x->x*2 end) 
 |>Enum.map(fn x->x+1 end)
 |>Enum.reduce(fn x,acc->x+acc end)
(new[] { 1, 2, 3 })
    .Select(x => x * 2)
    .Select(x => x + 1)
    .Aggregate((x, acc) => x + acc);

学んだこと

ほんの一部を勉強がてら試してみただけですが、ElixirのEnumの部分はLinqと共通点が多いので、Linq経験者には理解しやすいと感じました。

これから学ぼうとしている言語にとっつきやすさを少しでも感じられると、頭に入りやすいのでぼくとしてはとても良かったです。