Idiotproof

Map Reduce

プログラミング言語間のMap、Reduceの方法の比較

やっていること

  1. 1から10までの数字の配列を作成
  2. 偶数の値を取り出す
  3. 各値を2乗
  4. 合計する
  5. return 220

Java

IntStream.range(1, 11)
         .filter(n -> n % 2 == 0)
         .map(n -> n * n)
         .sum();

Scala

Range(1, 11).filter { _ % 2 == 0 }
            .map { n => n * n }
            .sum

インラインで書こうとするとsumが後置記法になってしまうので、代わりにreduce。 (一応「慣用的かつ許容し得る」らしい)

Range(1, 11) filter { _ % 2 == 0 } map { n => n * n } reduce { _ + _ }

Scala的にはドットを省略するべきだそうだが、 複数行のメソッドチェーンだとエラーになってしまう。どうするのがいいんだろう...。

val seq = for (i <- 1 to 11 if i % 2 == 0) yield i * i
seq.sum

yieldを使う場合。

Kotlin

IntRange(1, 11).filter { n -> n.mod(2) == 0 }
               .map { n -> n * n }
               .reduce { r, n -> r + n }

Clojure

(reduce (fn [r n] (+ r n))
  (map (fn [n] (* n n))
    (filter (fn [n] (= (rem n 2) 0))
      (range 1 11))))

マクロ

(->> (range 1 11)
  (filter even?)
  (map #(* % %))
  (reduce #(+ %1 %2)))

内包表記

(reduce #(+ %1 %2)
  (for [x (range 1 11) :when (even? x)]
    (* x x)))

Python

# 3系だとreduceを使うのにimportが必要
from functools import reduce

num = list(range(1, 11))
even = filter(lambda n: n % 2 == 0, num)
pow = map(lambda n: n * n, even)
res = reduce(lambda r, n: r + n, pow)
res = sum([n * n for n in nums if n % 2 == 0])

内包表記を使う方がPythonっぽいんだろうか。インラインで書くのもPythonらしくない気がする。

Ruby

num = 1..11
even = num.select { |n| n.even? }
pow = num.map { |n| n * n }       # collect
res = pow.reduce { |r, n| r + n } # inject

なんで同機能の異名メソッドがあるんですか(激怒)

PHP

$arr = range(1, 10); // inclusive
$even = array_filter($arr, function ($n) {
    return $n % 2 == 0;
});
$pow = array_map(function ($n) {
    return $n * $n;
}, $even);
// use array_sum() in production!
$res = array_reduce($pow, function ($rest, $n) {
    return $rest + $n;
});

C#

var num = ImmutableList.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
var even = num.Where(n => n % 2 == 0);
var pow = even.Select(n => n * n);
var res = pow.Sum();

LINQ

var pow = from n in Enumerable.Range(1, 11)
          where n % 2 == 0
          select n * n;
var res = pow.Aggregate((r, n) => r + n);

F#

let num = List.ofSeq(Enumerable.Range(1, 11))
let even = List.filter (fun n -> n % 2 = 0) num
let pow = List.map (fun n ->n * n) even
let res = List.reduce (fun r n -> r + n) pow

パイプライン演算子

[1..11]
|> List.filter (fun n -> n % 2 = 0)
|> List.map (fun n ->n * n)
|> List.sum

内包表記

[ for n in  1 .. 11 do if n % 2 = 0 then yield n * n] |> List.sum

参考