Scala 例 for Listの読み込み + Listの生成

Scalaのforも、やっぱりListをイテレートするのにつかう。
くわえて、Listをつくる機能もある。

このページはforだけ。Listそのものについては、こちら

別の日記
Scala 例 List - kaishitaeiichiの日記
Scaladoc
Scala Standard Library 2.12.8 - scala.collection.immutable.List

ふつうに見えるfor

以下、REPLで改行したときの記号|がはいっているからちょっと見にくくなるけど、

scala> for ( i <- 1 to 4) {
     |     println(i)
     | }
1
2
3
4

scala> for ( i <- 1 until 4) {
     |     println(i)
     | }
1
2
3

実際は、Scala Standard Library 2.12.8 - scala.collection.immutable.Rangeをiterate?しているようだ。

scala> 1 to 4
res11: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4)

scala> 1 until 4
res12: scala.collection.immutable.Range = Range(1, 2, 3)

どうやら、for ( i <- 1 to 4) という見た目で勘違いしてしまったが、Listのiterate処理そのものということらしい。

上の例では、iなんてつかっているけれど、Scalaのforは、Javaでいったら、

for(int i = 0; i < list.size(); i++) {
    A a = list.get(i);
}

こっちじゃなくて、

for(A a : list) {

}

こっちだ。

おなじみのやつをforループしてみよう。

scala> val list = List("a", "b", "c")
list: List[java.lang.String] = List(a, b, c)

scala> for( e <- list) {
     |     println(e)
     | }
a
b
c

scala> val map = Map(1 -> "a", 2 -> "b", 3 -> "c")
map: scala.collection.immutable.Map[Int,java.lang.String] = Map(1 -> a, 2 -> b, 3 -> c)

scala> for (e <- map) {
     |     println(e)
     | }
(1,a)
(2,b)
(3,c)

scala> val tuple = (1, "a", 'x)
tuple: (Int, java.lang.String, Symbol) = (1,a,'x)

scala> for( e <- tuple.productIterator ) {
     |     println(e)
     | }
1
a
'x

リスト内包表記

forループを使って、あるListからべつのListをつくるのは、Javaでもよくやる。

Scalaで、ListからListを生成するのは、Scala Standard Library 2.12.8 - scala.collection.immutable.Listのmapメソッドを真っ先におぼえて、一番つかっている気がする。

Scalaのforは、いわゆるリスト内包表記がつかえる。forを使って、Listを生成することができる。for + yield 生成するListの要素という書き方をする。

そういえば、HaskellPythonにも、リスト内包表記はあったなあ。

scala> for ( x <- 1 to 13 ) yield x
res20: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)

Listといいつつ、Vectorになってしまった。

forにListを2つ書けば、直積をつくることもできる。

scala> object Suit extends Enumeration { val HEART, DIA, SPADE, CLUB = Value}
defined module Suit

scala> for (suit <- Suit.values; cardNo <- 1 to 13) yield (suit, cardNo)
res10: scala.collection.immutable.Set[(Suit.Value, Int)] = Set((HEART,3), (CLUB,4), (CLUB,12), (DIA,1), (HEART,5), (SPADE,11), (CLUB,3), (HEART,4), (CLUB,5), (DIA,11), (CLUB,7), (DIA,3), (SPADE,12), (HEART,12), (SPADE,8), (SPADE,10), (SPADE,6), (DIA,2), (SPADE,3), (DIA,13), (SPADE,4), (CLUB,11), (CLUB,6), (SPADE,5), (SPADE,1), (DIA,12), (SPADE,9), (SPADE,2), (HEART,1), (HEART,8), (CLUB,8), (CLUB,13), (DIA,7), (DIA,6), (DIA,8), (CLUB,9), (HEART,11), (HEART,9), (CLUB,10), (SPADE,7), (CLUB,2), (HEART,10), (HEART,6), (HEART,7), (CLUB,1), (DIA,9), (SPADE,13), (HEART,2), (DIA,4), (HEART,13), (DIA,5), (DIA,10))

Listといいつつ、Setになってしまった。(suit, cardNo)はタプルだから、タプルのSet

ちょっと整理して、出力すると、

scala> (for (suit <- Suit.values; cardNo <- 1 to 13) yield (suit, cardNo)).toList.sorted foreach {
     |     card => card._2 match {
     |         case 13 => println(card)
     |         case _  => print(card)
     |     }
     | }
(HEART,1)(HEART,2)(HEART,3)(HEART,4)(HEART,5)(HEART,6)(HEART,7)(HEART,8)(HEART,9)(HEART,10)(HEART,11)(HEART,12)(HEART,13)
(DIA,1)(DIA,2)(DIA,3)(DIA,4)(DIA,5)(DIA,6)(DIA,7)(DIA,8)(DIA,9)(DIA,10)(DIA,11)(DIA,12)(DIA,13)
(SPADE,1)(SPADE,2)(SPADE,3)(SPADE,4)(SPADE,5)(SPADE,6)(SPADE,7)(SPADE,8)(SPADE,9)(SPADE,10)(SPADE,11)(SPADE,12)(SPADE,13)
(CLUB,1)(CLUB,2)(CLUB,3)(CLUB,4)(CLUB,5)(CLUB,6)(CLUB,7)(CLUB,8)(CLUB,9)(CLUB,10)(CLUB,11)(CLUB,12)(CLUB,13)