progs/lecture2.scala
changeset 268 e43f7e92ba26
parent 266 ca48ac1d3c3e
child 278 0c2481cd8b1c
equal deleted inserted replaced
267:9e0216756771 268:e43f7e92ba26
    16 
    16 
    17 val list = (1 to 1000000).toList
    17 val list = (1 to 1000000).toList
    18 time_needed(10, for (n <- list) yield n + 42)
    18 time_needed(10, for (n <- list) yield n + 42)
    19 time_needed(10, for (n <- list.par) yield n + 42)
    19 time_needed(10, for (n <- list.par) yield n + 42)
    20 
    20 
    21 // (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12)
    21 // (needs a library and 'magic' option -Yrepl-class-based)
    22 // (would need to have this wrapped into a function, or
       
    23 //  REPL called with scala -Yrepl-class-based)
       
    24 
    22 
    25 
    23 
    26 // Just for Fun: Mutable vs Immutable
    24 // Just for Fun: Mutable vs Immutable
    27 //====================================
    25 //====================================
    28 //
    26 //
   122 
   120 
   123 lst.map(x => (double(x), square(x)))
   121 lst.map(x => (double(x), square(x)))
   124 
   122 
   125 lst.map(square)
   123 lst.map(square)
   126 
   124 
   127 // this is actually what for is defined at in Scala
   125 // this is actually how for-comprehensions 
       
   126 // defined as in Scala
   128 
   127 
   129 lst.map(n => square(n))
   128 lst.map(n => square(n))
   130 for (n <- lst) yield square(n)
   129 for (n <- lst) yield square(n)
   131 
   130 
   132 // this can be iterated
   131 // this can be iterated
   225 
   224 
   226 ls.groupBy(_.length).get(2)
   225 ls.groupBy(_.length).get(2)
   227 
   226 
   228 
   227 
   229 
   228 
   230 // Option type
   229 // Option type (again)
   231 //=============
   230 //=====================
   232 
   231 
   233 //in Java if something unusually happens, you return null;
   232 // remember, in Java if something unusually happens, 
       
   233 // you return null;
   234 //
   234 //
   235 //in Scala you use Option
   235 // in Scala you use Option
   236 //   - if the value is present, you use Some(value)
   236 //   - if the value is present, you use Some(value)
   237 //   - if no value is present, you use None
   237 //   - if no value is present, you use None
   238 
   238 
   239 
   239 
   240 List(7,2,3,4,5,6).find(_ < 4)
   240 List(7,2,3,4,5,6).find(_ < 4)
   293  Try(Some(Integer.parseInt(s))).getOrElse(None)
   293  Try(Some(Integer.parseInt(s))).getOrElse(None)
   294 
   294 
   295 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
   295 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
   296 for (x <- lst) yield get_me_an_int(x)
   296 for (x <- lst) yield get_me_an_int(x)
   297 
   297 
   298 // summing all the numbers
   298 // summing up all the numbers
   299 
   299 
   300 lst.map(get_me_an_int).flatten.sum
   300 lst.map(get_me_an_int).flatten.sum
   301 lst.map(get_me_an_int).flatten.sum
   301 lst.map(get_me_an_int).flatten.sum
   302 
   302 
   303 
   303 
   417 }
   417 }
   418 
   418 
   419 fav_colour(Green)
   419 fav_colour(Green)
   420 
   420 
   421 
   421 
   422 // ... a bit more useful: Roman Numerals
   422 // ... a tiny bit more useful: Roman Numerals
   423 
   423 
   424 abstract class RomanDigit 
   424 abstract class RomanDigit 
   425 case object I extends RomanDigit 
   425 case object I extends RomanDigit 
   426 case object V extends RomanDigit 
   426 case object V extends RomanDigit 
   427 case object X extends RomanDigit 
   427 case object X extends RomanDigit 
   432 
   432 
   433 type RomanNumeral = List[RomanDigit] 
   433 type RomanNumeral = List[RomanDigit] 
   434 
   434 
   435 List(X,I)
   435 List(X,I)
   436 
   436 
       
   437 /*
   437 I -> 1
   438 I -> 1
   438 II -> 2
   439 II -> 2
   439 III  -> 3
   440 III  -> 3
   440 IV -> 4
   441 IV -> 4
   441 V -> 5
   442 V -> 5
   442 VI -> 6
   443 VI -> 6
   443 VII -> 7
   444 VII -> 7
   444 VIII -> 8
   445 VIII -> 8
   445 IX -> 9
   446 IX -> 9
   446 X -> X
   447 X -> X
       
   448 */
   447 
   449 
   448 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
   450 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
   449   case Nil => 0
   451   case Nil => 0
   450   case M::r    => 1000 + RomanNumeral2Int(r)  
   452   case M::r    => 1000 + RomanNumeral2Int(r)  
   451   case C::M::r => 900 + RomanNumeral2Int(r)
   453   case C::M::r => 900 + RomanNumeral2Int(r)
   508                   King, 
   510                   King, 
   509                   Clown)
   511                   Clown)
   510 
   512 
   511 println(people.sortWith(superior).mkString("\n"))
   513 println(people.sortWith(superior).mkString("\n"))
   512 
   514 
   513 print("123\\n456")
   515 
   514 
   516 // Tail Recursion
   515 
       
   516 // Tail recursion
       
   517 //================
   517 //================
   518 
   518 
   519 
   519 
   520 def fact(n: Long): Long = 
   520 def fact(n: Long): Long = 
   521   if (n == 0) 1 else n * fact(n - 1)
   521   if (n == 0) 1 else n * fact(n - 1)
   563 
   563 
   564 // regex for URLs and emails
   564 // regex for URLs and emails
   565 val http_pattern = """"https?://[^"]*"""".r
   565 val http_pattern = """"https?://[^"]*"""".r
   566 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r
   566 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r
   567 
   567 
       
   568 //test case:
   568 //email_pattern.findAllIn
   569 //email_pattern.findAllIn
   569 //  ("foo bla christian@kcl.ac.uk 1234567").toList
   570 //  ("foo bla christian@kcl.ac.uk 1234567").toList
   570 
   571 
   571 
   572 
   572 // drops the first and last character from a string
   573 // drops the first and last character from a string
   615               |..6.2..3.
   616               |..6.2..3.
   616               |1..5...92
   617               |1..5...92
   617               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
   618               |..7.9.41.""".stripMargin.replaceAll("\\n", "")
   618 
   619 
   619 type Pos = (Int, Int)
   620 type Pos = (Int, Int)
   620 val EmptyValue = '.'
   621 val emptyValue = '.'
   621 val MaxValue = 9
   622 val maxValue = 9
   622 
   623 
   623 val allValues = "123456789".toList
   624 val allValues = "123456789".toList
   624 val indexes = (0 to 8).toList
   625 val indexes = (0 to 8).toList
   625 
   626 
   626 
   627 
   627 
   628 def empty(game: String) = game.indexOf(emptyValue)
   628 
       
   629 def empty(game: String) = game.indexOf(EmptyValue)
       
   630 def isDone(game: String) = empty(game) == -1 
   629 def isDone(game: String) = empty(game) == -1 
   631 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue)
   630 def emptyPosition(game: String) : Pos = 
   632 
   631   (empty(game) % maxValue, empty(game) / maxValue)
   633 
   632 
   634 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col))
   633 
   635 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue))
   634 def get_row(game: String, y: Int) = indexes.map(col => game(y * maxValue + col))
       
   635 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * maxValue))
   636 
   636 
   637 def get_box(game: String, pos: Pos): List[Char] = {
   637 def get_box(game: String, pos: Pos): List[Char] = {
   638     def base(p: Int): Int = (p / 3) * 3
   638     def base(p: Int): Int = (p / 3) * 3
   639     val x0 = base(pos._1)
   639     val x0 = base(pos._1)
   640     val y0 = base(pos._2)
   640     val y0 = base(pos._2)
   641     val ys = (y0 until y0 + 3).toList
   641     for (x <- (x0 until x0 + 3).toList;
   642     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue)))
   642          y <- (y0 until y0 + 3).toList) yield game(x + y * maxValue)
   643 }
   643 }         
   644 
   644 
   645 
   645 
   646 //get_row(game0, 0)
   646 //get_row(game0, 0)
   647 //get_row(game0, 1)
   647 //get_row(game0, 1)
   648 //get_box(game0, (3,1))
   648 //get_box(game0, (3,1))
   649 
   649 
   650 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value)
   650 def update(game: String, pos: Int, value: Char): String = 
       
   651   game.updated(pos, value)
   651 
   652 
   652 def toAvoid(game: String, pos: Pos): List[Char] = 
   653 def toAvoid(game: String, pos: Pos): List[Char] = 
   653   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
   654   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos))
   654 
   655 
   655 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos)
   656 def candidates(game: String, pos: Pos): List[Char] = 
   656 
   657   allValues.diff(toAvoid(game, pos))
   657 //candidates(game0, (0,0))
   658 
   658 
   659 //candidates(game0, (0, 0))
   659 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n")
   660 
       
   661 def pretty(game: String): String = 
       
   662   "\n" ++ (game.sliding(maxValue, maxValue).mkString("\n"))
   660 
   663 
   661 def search(game: String): List[String] = {
   664 def search(game: String): List[String] = {
   662   if (isDone(game)) List(game)
   665   if (isDone(game)) List(game)
   663   else 
   666   else 
   664     candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten
   667     candidates(game, emptyPosition(game)).
   665 }
   668       map(c => search(update(game, empty(game), c))).flatten
   666 
   669 }
   667 
   670 
       
   671 // an easy game
   668 val game1 = """23.915...
   672 val game1 = """23.915...
   669               |...2..54.
   673               |...2..54.
   670               |6.7......
   674               |6.7......
   671               |..1.....9
   675               |..1.....9
   672               |89.5.3.17
   676               |89.5.3.17
   674               |......9.5
   678               |......9.5
   675               |.16..7...
   679               |.16..7...
   676               |...329..1""".stripMargin.replaceAll("\\n", "")
   680               |...329..1""".stripMargin.replaceAll("\\n", "")
   677 
   681 
   678 
   682 
   679 // game that is in the hard category
   683 // a game that is in the sligtly harder category
   680 val game2 = """8........
   684 val game2 = """8........
   681               |..36.....
   685               |..36.....
   682               |.7..9.2..
   686               |.7..9.2..
   683               |.5...7...
   687               |.5...7...
   684               |....457..
   688               |....457..
   685               |...1...3.
   689               |...1...3.
   686               |..1....68
   690               |..1....68
   687               |..85...1.
   691               |..85...1.
   688               |.9....4..""".stripMargin.replaceAll("\\n", "")
   692               |.9....4..""".stripMargin.replaceAll("\\n", "")
   689 
   693 
   690 // game with multiple solutions
   694 // a game with multiple solutions
   691 val game3 = """.8...9743
   695 val game3 = """.8...9743
   692               |.5...8.1.
   696               |.5...8.1.
   693               |.1.......
   697               |.1.......
   694               |8....5...
   698               |8....5...
   695               |...8.4...
   699               |...8.4...
   705 // for measuring time
   709 // for measuring time
   706 def time_needed[T](i: Int, code: => T) = {
   710 def time_needed[T](i: Int, code: => T) = {
   707   val start = System.nanoTime()
   711   val start = System.nanoTime()
   708   for (j <- 1 to i) code
   712   for (j <- 1 to i) code
   709   val end = System.nanoTime()
   713   val end = System.nanoTime()
   710   ((end - start) / i / 1.0e9) + " secs"
   714   s"${(end - start) / i / 1.0e9} secs"
   711 }
   715 }
   712 
   716 
   713 search(game2).map(pretty)
   717 search(game2).map(pretty)
   714 search(game3).distinct.length
   718 search(game3).distinct.length
   715 time_needed(3, search(game2))
   719 time_needed(3, search(game2))