かとじゅんの技術日誌

技術の話をするところ

今日のScala

とりあえず、リストの宣言

scala> var list = List(1,2,3,4,5)
list: List[Int] = List(1, 2, 3, 4, 5)

繰り返し処理をかいてみる。

scala> list.foreach(println)
1
2
3
4
5

これも同じことができる。

scala> for( i <- list ) println(i)
1
2
3
4
5

戻り値は返していない。偶数だけ返すにはこれ。

scala> list.filter(i => i % 2 == 0)
res20: List[Int] = List(2, 4)

アホみたいに簡単にかける。表示してみる。

scala> list.filter(i => i % 2 == 0).foreach(println)
2
4

さて、これをfor式で書いてみる。これもアホみたいに簡単でわかりやすい。

scala> for( i <- list if i % 2 == 0 ) println(i)
2
4

for式から戻り値を返す。

scala> for( i <- list if i % 2 == 0 ) yield i * 2
res27: List[Int] = List(4, 8)

これも等価。というか、上記は下記の構文糖衣。

scala> list.filter(i => i % 2 == 0).map(_*2)        
res28: List[Int] = List(4, 8)

追記:ymnkさんにご指摘をいただきました。上記のコードではなく下記になるそうです。無駄なリストの生成を抑える&if式の副作用がある場合でも意図通りの結果を得ることができるそうです

scala> list.withFilter(i => i % 2 == 0).map(_*2)        
res28: List[Int] = List(4, 8)

ymnkさんのこの投稿も参考になります。
Scala API - TraversableLike#withFilter 2.8 - scala--tohoku | Google グループ

追記:xuweiさんより、確かに完結に書ける。

list.collect{ case i if i % 2 == 0 => i * 2 }
というような書き方もできますよ

畳込み関数を使っていろいろやってみる。
まず最大値

scala> list.reduceLeft((a,b) => if (a > b) a else b) 
res13: Int = 5

scala> list.reduceLeft((a,b) => a max b)            
res14: Int = 5

Rubyぽくブロックでも書けるよと。

scala> list.reduceLeft{ (a,b) => a max b }
res15: Int = 5

まぁ、こんなことせずにmaxでOK。

scala> list.max
res24: Int = 5

reduceLeftはlistが空だと例外発生するので、空もあり得るならfoldLeftを使う。

追記:ymnkさんより、Optionに対応したreduceLeftとreduceRightがあるとのこと。これは便利。

scala> List.empty[Int].reduceLeftOption{ (a,b) => a max b }
res0: Option[Int] = None

scala> List(1,2,3).reduceLeftOption{ (a,b) => a max b }.getOrElse(error("empty!"))
res1: Int = 3

あと、リストが面白かったのはこれだ。

scala> var list2 = List(1,2,3)
list2: List[Int] = List(1, 2, 3)

scala> var list3 = 1 :: 2 :: 3 :: Nil
list3: List[Int] = List(1, 2, 3)

scala> var List(a,b,c) = list2
a: Int = 1
b: Int = 2
c: Int = 3

Nilは空のリストを意味する。