|      1 // Scala Lecture 2 |      1 // Scala Lecture 2 | 
|      2 //================= |      2 //================= | 
|      3  |      3  | 
|      4  |      4  | 
|         |      5 // Overloaded math operations | 
|         |      6  | 
|         |      7 (100 / 4) | 
|         |      8  | 
|         |      9 (100 / 3) | 
|         |     10  | 
|         |     11 (100.toDouble / 3.toDouble) | 
|         |     12  | 
|         |     13  | 
|         |     14 // For-Comprehensions again | 
|         |     15 //========================== | 
|         |     16  | 
|         |     17 def square(n: Int) : Int = n * n | 
|         |     18  | 
|         |     19 for (n <- (1 to 10).toList) yield { | 
|         |     20   val res = square(n) | 
|         |     21   res | 
|         |     22 } | 
|         |     23  | 
|         |     24 // like in functions, the "last" item inside the yield | 
|         |     25 // will be returned; the last item is not necessarily  | 
|         |     26 // the last line | 
|         |     27  | 
|         |     28 for (n <- (1 to 10).toList) yield { | 
|         |     29   if (n % 2 == 0) n  | 
|         |     30   else square(n) | 
|         |     31 } | 
|         |     32  | 
|         |     33  | 
|         |     34 // ...please, please do not write: | 
|         |     35 val lst = List(1, 2, 3, 4, 5, 6, 7, 8, 9) | 
|         |     36  | 
|         |     37 for (i <- (0 until lst.length).toList) yield square(lst(i)) | 
|         |     38  | 
|         |     39 // this is just so prone to off-by-one errors; | 
|         |     40 // write instead | 
|         |     41  | 
|         |     42 for (e <- lst) yield square(e) | 
|         |     43  | 
|         |     44  | 
|         |     45 //this works for sets as well | 
|         |     46 val st = Set(1, 2, 3, 4, 5, 6, 7, 8, 9) | 
|         |     47  | 
|         |     48 for (e <- st) yield { | 
|         |     49   if (e < 5) e else square(e) | 
|         |     50 } | 
|         |     51  | 
|         |     52  | 
|         |     53  | 
|         |     54 // Side-Effects | 
|         |     55 //============== | 
|         |     56  | 
|         |     57 // with only a side-effect (no list is produced), | 
|         |     58 // has no "yield" | 
|         |     59  | 
|         |     60 for (n <- (1 to 10)) println(n) | 
|         |     61  | 
|         |     62  | 
|         |     63 for (n <- (1 to 10)) { | 
|         |     64   print("The number is: ") | 
|         |     65   print(n) | 
|         |     66   print("\n") | 
|         |     67 } | 
|         |     68  | 
|         |     69  | 
|         |     70  | 
|         |     71  | 
|         |     72 // know when to use yield and when not: | 
|         |     73  | 
|         |     74 for (e <- Set(1, 2, 3, 4, 5, 6, 7, 8, 9); if e < 5) yield square(e) | 
|         |     75  | 
|         |     76  | 
|      5 // Option type |     77 // Option type | 
|      6 //============= |     78 //============= | 
|      7  |     79  | 
|      8 //in Java if something unusually happens, you return null; |     80 //in Java, if something unusually happens, you return null; | 
|      9 //in Scala you use Option |     81 //in Scala you use Option | 
|     10 //   - if the value is present, you use Some(value) |     82 //   - if the value is present, you use Some(value) | 
|     11 //   - if no value is present, you use None |     83 //   - if no value is present, you use None | 
|     12  |     84  | 
|     13  |     85  | 
|     14 List(7,2,3,4,5,6).find(_ < 4) |     86 List(7,2,3,4,5,6).find(_ < 4) | 
|     15 List(5,6,7,8,9).find(_ < 4) |     87 List(5,6,7,8,9).find(_ < 4) | 
|     16  |     88  | 
|     17  |     89  | 
|     18 // Values in types |     90 // some operations on Option's | 
|     19 // |         | 
|     20 // Boolean:  |         | 
|     21 // Int:  |         | 
|     22 // String:  |         | 
|     23 // |         | 
|     24 // Option[String]: |         | 
|     25 //    |         | 
|     26  |         | 
|     27  |     91  | 
|     28 val lst = List(None, Some(1), Some(2), None, Some(3)) |     92 val lst = List(None, Some(1), Some(2), None, Some(3)) | 
|     29  |     93  | 
|     30 lst.flatten |     94 lst.flatten | 
|     31  |     95  | 
|     38  |    102  | 
|     39 for ((x, y) <- ps) yield { |    103 for ((x, y) <- ps) yield { | 
|     40   if (y == 0) None else Some(x / y) |    104   if (y == 0) None else Some(x / y) | 
|     41 } |    105 } | 
|     42  |    106  | 
|     43 // getOrElse is for setting a default value |    107 // use .getOrElse is for setting a default value | 
|     44  |    108  | 
|     45 val lst = List(None, Some(1), Some(2), None, Some(3)) |    109 val lst = List(None, Some(1), Some(2), None, Some(3)) | 
|         |    110  | 
|     46 for (x <- lst) yield x.getOrElse(0) |    111 for (x <- lst) yield x.getOrElse(0) | 
|     47  |    112  | 
|     48  |    113  | 
|     49  |    114  | 
|     50  |    115  | 
|     51 // error handling with Option (no exceptions) |    116 // error handling with Options (no exceptions) | 
|         |    117 // | 
|         |    118 //  Try(....) | 
|     52 // |    119 // | 
|     53 //  Try(something).getOrElse(what_to_do_in_an_exception) |    120 //  Try(something).getOrElse(what_to_do_in_an_exception) | 
|     54 // |    121 // | 
|     55 import scala.util._ |    122 import scala.util._ | 
|         |    123  | 
|         |    124 Try(1 + 3) | 
|         |    125 Try(9 / 0)  | 
|         |    126  | 
|         |    127 Try(9 / 3).getOrElse(42)  | 
|         |    128 Try(9 / 0).getOrElse(42)  | 
|         |    129  | 
|         |    130  | 
|     56 import io.Source |    131 import io.Source | 
|     57  |    132  | 
|     58 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString |    133 val my_url = """https://nms.kcl.ac.uk/christian.urban""" | 
|     59  |    134  | 
|     60 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") |    135 Source.fromURL(my_url).mkString | 
|     61  |    136  | 
|     62 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) |    137 Try(Source.fromURL(my_url).mkString).getOrElse("") | 
|         |    138  | 
|         |    139 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None) | 
|         |    140  | 
|     63  |    141  | 
|     64 // a function that turns strings into numbers |    142 // a function that turns strings into numbers | 
|     65 Integer.parseInt("12u34") |    143 Integer.parseInt("1234") | 
|         |    144  | 
|     66  |    145  | 
|     67 def get_me_an_int(s: String): Option[Int] =  |    146 def get_me_an_int(s: String): Option[Int] =  | 
|     68  Try(Some(Integer.parseInt(s))).getOrElse(None) |    147  Try(Some(Integer.parseInt(s))).getOrElse(None) | 
|     69  |    148  | 
|     70 val lst = List("12345", "foo", "5432", "bar", "x21") |    149 val lst = List("12345", "foo", "5432", "bar", "x21") | 
|         |    150  | 
|     71 for (x <- lst) yield get_me_an_int(x) |    151 for (x <- lst) yield get_me_an_int(x) | 
|     72  |    152  | 
|     73 // summing all the numbers |    153 // summing all the numbers | 
|     74 val sum = lst.flatMap(get_me_an_int(_)).sum |    154 val sum = (for (i <- lst) yield get_me_an_int(i)).flatten.sum | 
|     75  |    155  | 
|     76  |    156  | 
|     77 // This may not look any better than working with null in Java, but to |    157 // This may not look any better than working with null in Java, but to | 
|     78 // see the value, you have to put yourself in the shoes of the |    158 // see the value, you have to put yourself in the shoes of the | 
|     79 // consumer of the get_me_an_int function, and imagine you didn't |    159 // consumer of the get_me_an_int function, and imagine you didn't | 
|     80 // write that function. |    160 // write that function. | 
|     81 // |    161 // | 
|     82 // In Java, if you didn't write this function, you'd have to depend on |    162 // In Java, if you didn't write this function, you'd have to depend on | 
|     83 // the Javadoc of the get_me_an_int. If you didn't look at the Javadoc,  |    163 // the Javadoc of get_me_an_int. If you didn't look at the Javadoc,  | 
|     84 // you might not know that get_me_an_int could return a null, and your  |    164 // you might not know that get_me_an_int could return a null, and your  | 
|     85 // code could potentially throw a NullPointerException. |    165 // code could potentially throw a NullPointerException. | 
|     86  |    166  | 
|     87  |    167  | 
|     88  |         | 
|     89 // even Scala is not immune to problems like this: |    168 // even Scala is not immune to problems like this: | 
|     90  |    169  | 
|     91 List(5,6,7,8,9).indexOf(7) |    170 List(5,6,7,8,9).indexOf(7) | 
|     92  |    171  | 
|         |    172  | 
|         |    173  | 
|         |    174  | 
|         |    175 // Higher-Order Functions | 
|         |    176 //======================== | 
|         |    177  | 
|         |    178 // functions can take functions as arguments | 
|         |    179  | 
|         |    180 val lst = (1 to 10).toList | 
|         |    181  | 
|         |    182 def even(x: Int) : Boolean = x % 2 == 0 | 
|         |    183 def odd(x: Int) : Boolean = x % 2 == 1 | 
|         |    184  | 
|         |    185 lst.filter(x => even(x)) | 
|         |    186 lst.filter(even(_)) | 
|         |    187 lst.filter(even) | 
|         |    188  | 
|         |    189 lst.find(_ > 8) | 
|         |    190  | 
|         |    191 // map applies a function to each element of a list | 
|         |    192  | 
|         |    193 def square(x: Int): Int = x * x | 
|         |    194  | 
|         |    195 lst.map(square) | 
|         |    196  | 
|         |    197 lst.map(square).filter(_ > 4) | 
|         |    198  | 
|         |    199 lst.map(square).filter(_ > 4).map(square) | 
|         |    200  | 
|         |    201 // map works for most collection types, including sets | 
|         |    202 Set(1, 3, 6).map(square) | 
|         |    203  | 
|         |    204  | 
|         |    205 // Why could functions as arguments be useful? | 
|         |    206 // | 
|         |    207 // Consider the sum between a and b: | 
|         |    208  | 
|         |    209 def sumInts(a: Int, b: Int) : Int =  | 
|         |    210   if (a > b) 0 else a + sumInts(a + 1, b) | 
|         |    211  | 
|         |    212  | 
|         |    213 sumInt(10, 16) | 
|         |    214  | 
|         |    215 // sum squares | 
|         |    216 def square(n: Int) : Int = n * n | 
|         |    217  | 
|         |    218 def sumSquares(a: Int, b: Int) : Int =  | 
|         |    219   if (a > b) 0 else square(a) + sumSquares(a + 1, b) | 
|         |    220  | 
|         |    221 sumSquares(2, 6) | 
|         |    222  | 
|         |    223  | 
|         |    224 // sum factorials | 
|         |    225 def fact(n: Int) : Int =   | 
|         |    226   if (n == 0) 1 else n * fact(n - 1) | 
|         |    227  | 
|         |    228 def sumFacts(a: Int, b: Int) : Int =  | 
|         |    229   if (a > b) 0 else fact(a) + sumFacts(a + 1, b) | 
|         |    230  | 
|         |    231 sumFacts(2, 6) | 
|         |    232  | 
|         |    233  | 
|         |    234  | 
|         |    235 // You can see the pattern....can we simplify out work? | 
|         |    236 // The type of functions from ints to ints: Int => Int | 
|         |    237  | 
|         |    238 def sum(f: Int => Int, a: Int, b: Int) : Int = { | 
|         |    239   if (a > b) 0  | 
|         |    240   else f(a) + sum(f, a + 1, b) | 
|         |    241 } | 
|         |    242  | 
|         |    243  | 
|         |    244 def sumSquares(a: Int, b: Int) : Int = sum(square, a, b) | 
|         |    245 def sumFacts(a: Int, b: Int) : Int = sum(fact, a, b) | 
|         |    246  | 
|         |    247 // What should we do for sumInts? | 
|         |    248  | 
|         |    249 def id(n: Int) : Int = n | 
|         |    250 def sumInts(a: Int, b: Int) : Int = sum(id, a, b) | 
|         |    251  | 
|         |    252  | 
|         |    253  | 
|         |    254 // Anonymous Functions: You can also write: | 
|         |    255  | 
|         |    256 def sumCubes(a: Int, b: Int) : Int =   sum(x => x * x * x, a, b) | 
|         |    257 def sumSquares(a: Int, b: Int) : Int = sum(x => x * x, a, b) | 
|         |    258 def sumInts(a: Int, b: Int) : Int    = sum(x => x, a, b) | 
|         |    259  | 
|         |    260  | 
|         |    261 // other function types | 
|         |    262 // | 
|         |    263 // f1: (Int, Int) => Int | 
|         |    264 // f2: List[String] => Option[Int] | 
|         |    265 // ...  | 
|         |    266  | 
|         |    267  | 
|         |    268 // Function Composition | 
|         |    269 //====================== | 
|         |    270  | 
|         |    271 // How could Higher-Order Functions and Options be helpful? | 
|         |    272  | 
|         |    273 def add_footer(msg: String) : String = msg ++ " - Sent from iOS" | 
|         |    274  | 
|         |    275 def valid_msg(msg: String) : Boolean = msg.size <= 140 | 
|         |    276  | 
|         |    277 def duplicate(s: String) : String = s ++ s | 
|         |    278  | 
|         |    279 // they compose nicely | 
|         |    280 valid_msg(add_footer("Hello World")) | 
|         |    281 valid_msg(duplicate(add_footer("Hello World"))) | 
|         |    282  | 
|         |    283  | 
|         |    284 // first_word: let's first do it the ugly Java way using null: | 
|         |    285  | 
|         |    286 def first_word(msg: String) : String = { | 
|         |    287   val words = msg.split(" ") | 
|         |    288   if (words(0) != "") words(0) else null | 
|         |    289 } | 
|         |    290  | 
|         |    291 duplicate(first_word("Hello World")) | 
|         |    292 duplicate(first_word("")) | 
|         |    293  | 
|         |    294 def extended_duplicate(s: String) : String =  | 
|         |    295   if (s != null) s ++ s else null | 
|         |    296  | 
|         |    297 extended_duplicate(first_word("")) | 
|         |    298  | 
|         |    299  | 
|         |    300 // Avoid always null! | 
|         |    301 def better_first_word(msg: String) : Option[String] = { | 
|         |    302   val words = msg.split(" ") | 
|         |    303   if (words(0) != "") Some(words(0)) else None | 
|         |    304 } | 
|         |    305  | 
|         |    306 better_first_word("Hello World").map(duplicate) | 
|         |    307 better_first_word("Hello World").map(duplicate).map(duplicate).map(valid_msg) | 
|         |    308  | 
|         |    309 better_first_word("").map(duplicate) | 
|         |    310 better_first_word("").map(duplicate).map(valid_msg) | 
|     93  |    311  | 
|     94  |    312  | 
|     95  |    313  | 
|     96  |    314  | 
|     97 // Type abbreviations |    315 // Type abbreviations | 
|     98 //==================== |    316 //==================== | 
|     99  |    317  | 
|    100 // some syntactic convenience |    318 // some syntactic convenience | 
|         |    319  | 
|    101 type Pos = (int, Int) |    320 type Pos = (int, Int) | 
|    102  |         | 
|    103 type Board = List[List[Int]] |    321 type Board = List[List[Int]] | 
|    104  |    322  | 
|    105  |    323  | 
|    106  |    324  | 
|    107 // Implicits |    325 // Implicits (Cool Feature) | 
|    108 //=========== |    326 //========================= | 
|    109 // |    327 // | 
|    110 // for example adding your own methods to Strings: |    328 // For example adding your own methods to Strings: | 
|    111 // imagine you want to increment strings, like |    329 // Imagine you want to increment strings, like | 
|    112 // |    330 // | 
|    113 //     "HAL".increment |    331 //     "HAL".increment | 
|    114 // |    332 // | 
|    115 // you can avoid ugly fudges, like a MyString, by |    333 // you can avoid ugly fudges, like a MyString, by | 
|    116 // using implicit conversions |    334 // using implicit conversions. | 
|    117  |    335  | 
|    118  |    336  | 
|    119 implicit class MyString(s: String) { |    337 implicit class MyString(s: String) { | 
|    120   def increment = for (c <- s) yield (c + 1).toChar  |    338   def increment = for (c <- s) yield (c + 1).toChar  | 
|    121 } |    339 } | 
|    122  |    340  | 
|    123 "HAL".increment |    341 "HAL".increment | 
|    124  |    342  | 
|    125  |    343  | 
|    126 // No return in Scala |    344  | 
|         |    345 // No returns in Scala | 
|    127 //==================== |    346 //==================== | 
|    128  |    347  | 
|    129 //You should not use "return" in Scala: |    348 // You should not use "return" in Scala: | 
|    130 // |    349 // | 
|    131 // A return expression, when evaluated, abandons the  |    350 // A return expression, when evaluated, abandons the  | 
|    132 // current computation and returns to the caller of the  |    351 // current computation and returns to the caller of the  | 
|    133 // function in which return appears." |    352 // function in which return appears." | 
|    134  |    353  | 
|    135 def sq1(x: Int): Int = x * x |    354 def sq1(x: Int): Int = x * x | 
|    136 def sq2(x: Int): Int = return x * x |    355 def sq2(x: Int): Int = return x * x | 
|    137  |    356  | 
|    138 def sumq(ls: List[Int]): Int = { |    357 def sumq(ls: List[Int]): Int = { | 
|    139   (for (x <- ls) yield (return x * x)).sum[Int] |    358   ls.map(sq1).sum[Int] | 
|    140 } |    359 } | 
|    141  |    360  | 
|    142 sumq(List(1,2,3,4)) |    361 sumq(List(1, 2, 3, 4)) | 
|    143  |    362  | 
|    144  |    363  | 
|    145 // last expression in a function is the return statement |    364  | 
|    146 def square(x: Int): Int = { |    365 def sumq(ls: List[Int]): Int = { | 
|    147   println(s"The argument is ${x}.") |    366   val sqs : List[Int] = for (x <- ls) yield (return x * x) | 
|    148   x * x |    367   sqs.sum | 
|    149 } |    368 } | 
|         |    369  | 
|    150  |    370  | 
|    151  |    371  | 
|    152  |    372  | 
|    153 // Pattern Matching |    373 // Pattern Matching | 
|    154 //================== |    374 //================== | 
|    209  |    428  | 
|    210 // What happens if no case matches? |    429 // What happens if no case matches? | 
|    211  |    430  | 
|    212 println(season("foobar")) |    431 println(season("foobar")) | 
|    213  |    432  | 
|         |    433  | 
|    214 // User-defined Datatypes |    434 // User-defined Datatypes | 
|    215 //======================== |    435 //======================== | 
|    216  |    436  | 
|    217 abstract class Tree |    437 abstract class Colour | 
|    218 case class Node(elem: Int, left: Tree, right: Tree) extends Tree |    438 case class Red() extends Colour  | 
|    219 case class Leaf() extends Tree |    439 case class Green() extends Colour  | 
|    220  |    440 case class Blue() extends Colour | 
|    221  |    441  | 
|    222 def insert(tr: Tree, n: Int): Tree = tr match { |    442 def fav_colour(c: Colour) : Boolean = c match { | 
|    223   case Leaf() => Node(n, Leaf(), Leaf()) |    443   case Red()   => false | 
|    224   case Node(m, left, right) =>  |    444   case Green() => true | 
|    225     if (n == m) Node(m, left, right)  |    445   case Blue()  => false  | 
|    226     else if (n < m) Node(m, insert(left, n), right) |    446 } | 
|    227     else Node(m, left, insert(right, n)) |    447  | 
|    228 } |    448  | 
|    229  |    449 // actually this can be written with "object" | 
|    230  |    450  | 
|    231 val t1 = Node(4, Node(2, Leaf(), Leaf()), Node(7, Leaf(), Leaf())) |         | 
|    232 insert(t1, 3) |         | 
|    233  |         | 
|    234 def depth(tr: Tree): Int = tr match { |         | 
|    235   case Leaf() => 0 |         | 
|    236   case Node(_, left, right) => 1 + List(depth(left), depth(right)).max |         | 
|    237 } |         | 
|    238  |         | 
|    239  |         | 
|    240 def balance(tr: Tree): Int = tr match { |         | 
|    241   case Leaf() => 0 |         | 
|    242   case Node(_, left, right) => depth(left) - depth(right) |         | 
|    243 } |         | 
|    244  |         | 
|    245 balance(insert(t1, 3)) |         | 
|    246  |    451  | 
|    247 // another example |    452 // another example | 
|         |    453 //================= | 
|    248  |    454  | 
|    249 abstract class Person |    455 abstract class Person | 
|    250 case class King() extends Person |    456 case class King() extends Person | 
|    251 case class Peer(deg: String, terr: String, succ: Int) extends Person |    457 case class Peer(deg: String, terr: String, succ: Int) extends Person | 
|    252 case class Knight(name: String) extends Person |    458 case class Knight(name: String) extends Person | 
|    253 case class Peasant(name: String) extends Person |    459 case class Peasant(name: String) extends Person | 
|    254 case class Clown() extends Person |    460  | 
|    255  |    461  | 
|    256 def title(p: Person): String = p match { |    462 def title(p: Person): String = p match { | 
|    257   case King() => "His Majesty the King" |    463   case King() => "His Majesty the King" | 
|    258   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" |    464   case Peer(deg, terr, _) => s"The ${deg} of ${terr}" | 
|    259   case Knight(name) => s"Sir ${name}" |    465   case Knight(name) => s"Sir ${name}" | 
|    260   case Peasant(name) => name |    466   case Peasant(name) => name | 
|    261 } |    467 } | 
|         |    468  | 
|    262  |    469  | 
|    263 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { |    470 def superior(p1: Person, p2: Person): Boolean = (p1, p2) match { | 
|    264   case (King(), _) => true |    471   case (King(), _) => true | 
|    265   case (Peer(_,_,_), Knight(_)) => true |    472   case (Peer(_,_,_), Knight(_)) => true | 
|    266   case (Peer(_,_,_), Peasant(_)) => true |    473   case (Peer(_,_,_), Peasant(_)) => true | 
|    279  |    486  | 
|    280 println(people.sortWith(superior(_, _)).mkString(", ")) |    487 println(people.sortWith(superior(_, _)).mkString(", ")) | 
|    281  |    488  | 
|    282  |    489  | 
|    283  |    490  | 
|    284 // Higher-Order Functions |    491  | 
|    285 //======================== |    492  | 
|    286  |    493  | 
|    287 // functions can take functions as arguments |    494 // Problems with mutability and parallel computations | 
|    288  |    495 //==================================================== | 
|    289 val lst = (1 to 10).toList |    496  | 
|    290  |    497 def count_intersection(A: Set[Int], B: Set[Int]) : Int = { | 
|    291 def even(x: Int): Boolean = x % 2 == 0 |    498   var count = 0 | 
|    292 def odd(x: Int): Boolean = x % 2 == 1 |    499   for (x <- A; if (B contains x)) count += 1  | 
|    293  |    500   count | 
|    294 lst.filter(x => even(x)) |    501 } | 
|    295 lst.filter(even(_)) |    502  | 
|    296 lst.filter(even) |    503 val A = (1 to 1000).toSet | 
|    297  |    504 val B = (1 to 1000 by 4).toSet | 
|    298 lst.find(_ > 8) |    505  | 
|    299  |    506 count_intersection(A, B) | 
|    300 def square(x: Int): Int = x * x |    507  | 
|    301  |    508 // but do not try to add .par to the for-loop above | 
|    302 lst.map(square) |    509  | 
|    303  |    510  | 
|    304 lst.map(square).filter(_ > 4) |    511 //propper parallel version | 
|    305  |    512 def count_intersection2(A: Set[Int], B: Set[Int]) : Int =  | 
|    306 lst.map(square).filter(_ > 4).map(square) |    513   A.par.count(x => B contains x) | 
|    307  |    514  | 
|    308 // in my collatz.scala |    515 count_intersection2(A, B) | 
|    309 //(1 to bnd).map(i => (collatz(i), i)).maxBy(_._1) |    516  | 
|    310  |    517  | 
|    311  |    518 //for measuring time | 
|    312 // type of functions, for example f: Int => Int |    519 def time_needed[T](n: Int, code: => T) = { | 
|    313  |    520   val start = System.nanoTime() | 
|    314 def my_map_int(lst: List[Int], f: Int => Int): List[Int] = lst match { |    521   for (i <- (0 to n)) code | 
|    315   case Nil => Nil |    522   val end = System.nanoTime() | 
|    316   case x::xs => f(x)::my_map_int(xs, f) |    523   (end - start) / 1.0e9 | 
|    317 } |    524 } | 
|    318  |    525  | 
|    319 my_map_int(lst, square) |    526 val A = (1 to 1000000).toSet | 
|    320  |    527 val B = (1 to 1000000 by 4).toSet | 
|    321 // other function types |    528  | 
|    322 // |    529 time_needed(10, count_intersection(A, B)) | 
|    323 // f1: (Int, Int) => Int |    530 time_needed(10, count_intersection2(A, B)) | 
|    324 // f2: List[String] => Option[Int] |    531  | 
|    325 // ...  |    532  | 
|    326  |         | 
|    327  |         | 
|    328 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |         | 
|    329   case Nil => 0 |         | 
|    330   case x::xs => f(x) + sumOf(f, xs) |         | 
|    331 } |         | 
|    332  |         | 
|    333 def sum_squares(lst: List[Int]) = sumOf(square, lst) |         | 
|    334 def sum_cubes(lst: List[Int])   = sumOf(x => x * x * x, lst) |         | 
|    335  |         | 
|    336 sum_squares(lst) |         | 
|    337 sum_cubes(lst) |         | 
|    338  |         | 
|    339 // lets try it factorial |         | 
|    340 def fact(n: Int): Int = ... |         | 
|    341  |         | 
|    342 def sum_fact(lst: List[Int]) = sumOf(fact, lst) |         | 
|    343 sum_fact(lst) |         | 
|    344  |         | 
|    345 // Avoid being mutable |         | 
|    346 //===================== |         | 
|    347  |         | 
|    348 // a student showed me... |         | 
|    349 import scala.collection.mutable.ListBuffer |         | 
|    350  |         | 
|    351  |         | 
|    352  |         | 
|    353 def collatz_max(bnd: Long): (Long, Long) = { |         | 
|    354   val colNos = ListBuffer[(Long, Long)]() |         | 
|    355   for (i <- (1L to bnd).toList) colNos += ((collatz(i), i)) |         | 
|    356   colNos.max |         | 
|    357 } |         | 
|    358  |         | 
|    359 def collatz_max(bnd: Long): (Long, Long) = { |         | 
|    360   (1L to bnd).map((i) => (collatz(i), i)).maxBy(_._1) |         | 
|    361 } |         | 
|    362  |         | 
|    363 //views -> lazy collection |         | 
|    364 def collatz_max(bnd: Long): (Long, Long) = { |         | 
|    365   (1L to bnd).view.map((i) => (collatz(i), i)).maxBy(_._1) |         | 
|    366 } |         | 
|    367  |         | 
|    368 // raises a GC exception |         | 
|    369 (1 to 1000000000).filter(_ % 2 == 0).take(10).toList |         | 
|    370 // ==> java.lang.OutOfMemoryError: GC overhead limit exceeded |         | 
|    371  |         | 
|    372 (1 to 1000000000).view.filter(_ % 2 == 0).take(10).toList |         | 
|    373  |    533  | 
|    374  |    534  | 
|    375  |    535  | 
|    376 // Sudoku |    536 // Sudoku | 
|    377 //======== |    537 //======== | 
|    397  |    557  | 
|    398 val allValues = "123456789".toList |    558 val allValues = "123456789".toList | 
|    399 val indexes = (0 to 8).toList |    559 val indexes = (0 to 8).toList | 
|    400  |    560  | 
|    401  |    561  | 
|    402  |         | 
|    403  |         | 
|    404 def empty(game: String) = game.indexOf(EmptyValue) |    562 def empty(game: String) = game.indexOf(EmptyValue) | 
|    405 def isDone(game: String) = empty(game) == -1  |    563 def isDone(game: String) = empty(game) == -1  | 
|    406 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) |    564 def emptyPosition(game: String) = (empty(game) % MaxValue, empty(game) / MaxValue) | 
|    407  |    565  | 
|    408  |    566  | 
|    409 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col)) |    567 def get_row(game: String, y: Int) = indexes.map(col => game(y * MaxValue + col)) | 
|    410 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue)) |    568 def get_col(game: String, x: Int) = indexes.map(row => game(x + row * MaxValue)) | 
|         |    569  | 
|         |    570 get_row(game0, 3) | 
|         |    571 get_col(game0, 0) | 
|    411  |    572  | 
|    412 def get_box(game: String, pos: Pos): List[Char] = { |    573 def get_box(game: String, pos: Pos): List[Char] = { | 
|    413     def base(p: Int): Int = (p / 3) * 3 |    574     def base(p: Int): Int = (p / 3) * 3 | 
|    414     val x0 = base(pos._1) |    575     val x0 = base(pos._1) | 
|    415     val y0 = base(pos._2) |    576     val y0 = base(pos._2) | 
|    416     val ys = (y0 until y0 + 3).toList |    577     val ys = (y0 until y0 + 3).toList | 
|    417     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) |    578     (x0 until x0 + 3).toList.flatMap(x => ys.map(y => game(x + y * MaxValue))) | 
|    418 } |    579 } | 
|    419  |    580  | 
|    420  |    581 get_box(game0, (0, 0)) | 
|    421 //get_row(game0, 0) |    582 get_box(game0, (1, 1)) | 
|    422 //get_row(game0, 1) |    583 get_box(game0, (2, 1)) | 
|    423 //get_box(game0, (3,1)) |    584  | 
|    424  |    585 // this is not mutable!! | 
|    425 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) |    586 def update(game: String, pos: Int, value: Char): String = game.updated(pos, value) | 
|    426  |    587  | 
|    427 def toAvoid(game: String, pos: Pos): List[Char] =  |    588 def toAvoid(game: String, pos: Pos): List[Char] =  | 
|    428   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) |    589   (get_col(game, pos._1) ++ get_row(game, pos._2) ++ get_box(game, pos)) | 
|    429  |    590  | 
|    430 def candidates(game: String, pos: Pos): List[Char] = allValues diff toAvoid(game,pos) |    591 def candidates(game: String, pos: Pos): List[Char] = allValues.diff(toAvoid(game,pos)) | 
|    431  |    592  | 
|    432 //candidates(game0, (0,0)) |    593 //candidates(game0, (0,0)) | 
|    433  |    594  | 
|    434 def pretty(game: String): String = "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") |    595 def pretty(game: String): String =  | 
|         |    596   "\n" + (game sliding (MaxValue, MaxValue) mkString "\n") | 
|    435  |    597  | 
|    436 def search(game: String): List[String] = { |    598 def search(game: String): List[String] = { | 
|    437   if (isDone(game)) List(game) |    599   if (isDone(game)) List(game) | 
|    438   else  |    600   else { | 
|    439     candidates(game, emptyPosition(game)).map(c => search(update(game, empty(game), c))).toList.flatten |    601     val cs = candidates(game, emptyPosition(game)) | 
|    440 } |    602     cs.map(c => search(update(game, empty(game), c))).toList.flatten | 
|    441  |    603   } | 
|         |    604 } | 
|         |    605  | 
|         |    606 search(game0).map(pretty) | 
|    442  |    607  | 
|    443 val game1 = """23.915... |    608 val game1 = """23.915... | 
|    444               |...2..54. |    609               |...2..54. | 
|    445               |6.7...... |    610               |6.7...... | 
|    446               |..1.....9 |    611               |..1.....9 |