scala.util.Randomで乱数を生成する。

1から10までのランダムな数をつくるのはどうやるんだろう。

Scala Standard Library 2.12.8 - scala.util.Randomを見てみたが、おおむねjava.util.Randomとおなじか?

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@5f04eb

scala> r.nextInt
res173: Int = -49067135

scala> r.nextInt(10)
res175: Int = 4

scala> r.nextInt(10) + 1
res176: Int = 1

ランダムな数字のリストがほしい

scala> r.shuffle((1 to 10).toSeq)
res37: scala.collection.immutable.IndexedSeq[Int] = Vector(7, 4, 8, 9, 1, 3, 10, 5, 2, 6)

ちょっとちがうかな。

こうかなあ

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> r10
res168: Int = 10

scala> r10
res169: Int = 1

scala> def infinitR10: Stream[Int] = Stream.cons(r10, infinitR10)
infinitR10: Stream[Int]

scala> infinitR10 take 20
res171: scala.collection.immutable.Stream[Int] = Stream(6, ?)

scala> infinitR10 take 20 foreach println
10
2
1
8
6
6
4
8
5
4
9
7
10
2
6
7
6
2
4
10

scala>

あれ?なんか数が偏っている?一様になってないかな。うーん。集計してみる。

scala> b.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     |     acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
res208: scala.collection.immutable.Map[Int,Int] = Map(5 -> 6, 1 -> 1, 6 -> 2, 9 -> 3, 2 -> 2, 7 -> 1, 3 -> 1, 8 -> 2, 4 -> 2)

scala> val c = infinitR10 take 10000
c: scala.collection.immutable.Stream[Int] = Stream(4, ?)

scala> c.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     |     acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
res209: scala.collection.immutable.Map[Int,Int] = Map(5 -> 1038, 10 -> 1028, 1 -> 964, 6 -> 1008, 9 -> 1011, 2 -> 1018, 7 -> 1009, 3 -> 1000, 8 -> 930, 4 -> 994)

もっと多くのデータで!

ヒープのサイズを増やして、ScalaのREPLを起動しなおす。

F:\Data\ProgrammingLanguage\Scala\play-projects>scala -DXmx1024m
Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) Client VM, Java 1.7.0_02).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@d7ba5b

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> def infinitR10: Stream[Int] = Stream.cons(r10, infinitR10)
infinitR10: Stream[Int]

scala> val d = infinitR10 take 1000000
d: scala.collection.immutable.Stream[Int] = Stream(1, ?)

scala> val result = d.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     | acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
result: scala.collection.immutable.Map[Int,Int] = Map(5 -> 100161, 10 -> 99790, 1 -> 99934, 6 -> 99675, 9 -> 99919, 2 -> 99738, 7 -> 99758, 3 -> 100131, 8 -> 100429, 4 -> 100465)

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> val result2 = TreeMap[Int, Int]()
result2: scala.collection.immutable.TreeMap[Int,Int] = Map()

scala> result2 ++ result
res6: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 99934, 2 -> 99738, 3 -> 100131, 4 -> 100465, 5 -> 100161, 6 -> 99675, 7 -> 99758, 8 -> 100429, 9 -> 99919, 10 -> 99790)

scala>

さらに要素の数を1000000から10000000にしたら、Out Of Memoryになってしまった。そうならないためのStreamではないのか?自分がなにかまちがっているのか。うーん。。。。

Scala Standard Library 2.12.8 - scala.collection.immutable.Streamにある例のIteratorを使う方法を試してみる。

scala> import scala.util.Random
import scala.util.Random

scala> val r = new Random
r: scala.util.Random = scala.util.Random@d7ba5b

scala> def r10 = r.nextInt(10) + 1
r10: Int

scala> val it = new Iterator[Int] {
     | def hasNext = true
     | def next: Int = { r10 }
     | }
it: java.lang.Object with Iterator[Int] = non-empty iterator

scala> val d = it take 100000000
d: Iterator[Int] = non-empty iterator

scala> val result = d.foldLeft (Map[Int, Int]()) { (acc: Map[Int, Int], e: Int) =>
     | acc + (e -> (acc.getOrElse(e, 0) + 1))
     | }
result: scala.collection.immutable.Map[Int,Int] = Map(5 -> 9999613, 10 -> 9998925, 1 -> 10005035, 6 -> 10004810, 9 -> 9992785, 2 -> 9995009, 7 -> 9999772, 3 -> 10002721, 8 -> 10000349, 4 -> 10000981)

scala> import scala.collection.immutable.TreeMap
import scala.collection.immutable.TreeMap

scala> val result2 = TreeMap[Int, Int]()
result2: scala.collection.immutable.TreeMap[Int,Int] = Map()

scala> result2 ++ result
res7: scala.collection.immutable.TreeMap[Int,Int] = Map(1 -> 10005035, 2 -> 9995009, 3 -> 10002721, 4 -> 10000981, 5 -> 9999613, 6 -> 10004810, 7 -> 9999772, 8 -> 10000349, 9 -> 9992785, 10 -> 9998925)

scala>

おおー、Iteratorだと、10000000どころか100000000でもだいじょうぶだ。

もはや、主題がRandomのはなしでなくなってしまったが、、、、Streamはつかいかたは、勉強だな。とりあえずは、Iteratorがお手軽だと。