Scala脳のための C# LINQ
これは Scala プログラマのための C# LINQ 機能の覚え書きだが、逆としても使えるはず。
型推論
C# には型推論がある。個人的に、ローカル変数ではできるだけ var を使うようにしている。
Scala にも var があるけど、可能なら不変 (immutable) な val を使うのが好ましいとされている。
val x = 1
新しい List と Array の作成
C# はインラインでコレクションを作ることができる。
var list = new List
全ての Scala コレクションにファクトリメソッドがある。
val list = List("Adam", "Alice", "Bob", "Charlie")
val array = Array(0, 1, 2)
ラムダ式を使ったフィルタ
C# には “enrich-my-library” 的なモンキーパッチングがあり、普通の Array に Where メソッドが追加されている。
var xs = array.Where(x => x >= 1);
これは Scala では何通りかの書き方がある。
array.filter(x => x >= 1)
array filter { _ >= 1 }
array filter { 1 <= }
投射
C# での投射は Select と SelectMany によって行われる。
これは map と flatMap に対応する。
array map { _ + 1 }
array flatMap { Array(_, 3) }
ソート
C# は OrderBy を使ってソートすることができる。
Scala で何かをソートする必要があったことが思い出せないけど、sortBy を使えばできる。
list sortBy { _.length }
クエリ式を使ったフィルタ
いよいよクエリ式 (query expression) の登場。
Scala でこれに近いものだと多分 for 内包表記 (for comprehension) だと思う。
for (x <- array if x >= 1)
  yield x
これに似たようなものも C# で書けるんだけど、Scala と違って foreach が値を返さないから、まるごとメソッドでラッピングする必要がある。
クエリ式を使った投射
暗黙型 (anonymous type) への投射を C# で試そう。
Scala は for 内包表記で。
for (x <- array)
  yield new { def foo = x + 1 }
中間値によるソート
中間値を用いてソートする。
var results = from x in list let cs = new Regex(@"[aeiou]").Replace(x.ToLower(), “”) orderby cs.Length select x;
Scala の for 内包表記ではソートできないけど、後付けでソートできる。
list sortBy { x =>
  val cs = """[aeiou]""".r.replaceAllIn(x.toLowerCase, "")
  cs.length
}
クロスジョイン
この SQLっぽさは C# でジョインで便利になってくる。
Scala は for 内包表記で。
for {
  x <- list
  c <- x.toCharArray
  if c != 'a' && c != 'e'
} yield c
インナージョイン
C# でのインナージョイン。
Scala は for 内包表記で。
for {
  name <- list
  n <- array if name.length == n + 3
} yield (name, n)
グループ化
C# でのグループ化。
for 内包表記じゃないけど、Scala でも可能。
list groupBy { _(0) } filter { case (k, vs) =>
  vs.size > 1 }
限定子
限定子 (quantifier) はだいたい同じように動作する。
Scala では。
val hasThree = list exists { _.length == 3 }
val allThree = list forall { _.length == 3 }
パターンマッチング
Scala に特徴的なのはラムダ式が期待されている所に部分関数 (partial function) を渡すことができることだ。
array map {
  case 1 => "foo"
  case n if n % 2 == 0 => n.toString + "!"
}
C# でこれを真似するには自分で例外を投げる必要があると思う。
感想
Scala では、for 内包表記よりも普通の filter とか map を呼び出すのが好みだ。演算子の中置記法とプレースホルダ構文のお陰で array filter { _ >= 1 } が十分簡潔になってるから、入れ子で使わない限りは for 内包表記の方が見た目が大きくなっている。
一方 C# は、クエリ式の構文はメソッド構文からいくつかのシンボルを (., (), =>) を取り除いている。
ここで書ききれなかったことの全ては、Rahul (@missingfaktor) が Enumerable のメソッドとそれに対応する Scala のコードという形でまとめている。