51   | 
    49   | 
    52 // some alterative syntax for lists  | 
    50 // some alterative syntax for lists  | 
    53   | 
    51   | 
    54 1 :: 2 :: 3 :: Nil  | 
    52 1 :: 2 :: 3 :: Nil  | 
    55 List(1, 2, 3) ::: List(4, 5, 6)  | 
    53 List(1, 2, 3) ::: List(4, 5, 6)  | 
         | 
    54   | 
         | 
    55 // Equality is structural  | 
         | 
    56 //========================  | 
         | 
    57 val a = "Dave"  | 
         | 
    58 val b = "Dave"  | 
         | 
    59   | 
         | 
    60 if (a == b) println("equal") else println("unequal") | 
         | 
    61   | 
         | 
    62 Set(1,2,3) == Set(3,1,2)  | 
         | 
    63 List(1,2,3) == List(3,1,2)  | 
         | 
    64   | 
         | 
    65   | 
         | 
    66 // this applies for "concrete" values;  | 
         | 
    67 // you cannot compare functions  | 
         | 
    68   | 
    56   | 
    69   | 
    57 // Printing/Strings  | 
    70 // Printing/Strings  | 
    58 //==================  | 
    71 //==================  | 
    59   | 
    72   | 
    60 println("test") | 
    73 println("test") | 
    89 List(1,2,3,4).max  | 
   102 List(1,2,3,4).max  | 
    90 List(1,2,3,4).min  | 
   103 List(1,2,3,4).min  | 
    91 List(1,2,3,4).sum  | 
   104 List(1,2,3,4).sum  | 
    92 List(1,2,3,4).take(2).sum  | 
   105 List(1,2,3,4).take(2).sum  | 
    93 List(1,2,3,4).drop(2).sum  | 
   106 List(1,2,3,4).drop(2).sum  | 
    94 List(1,2,3,4,3)indexOf(3)  | 
   107 List(1,2,3,4,3).indexOf(3)  | 
    95   | 
   108   | 
    96 "1,2,3,4,5".split(",").mkString("\n") | 
   109 "1,2,3,4,5".split(",").mkString("\n") | 
    97 "1,2,3,4,5".split(",3,").mkString("\n") | 
   110 "1,2,3,4,5".split(",3,").mkString("\n") | 
    98   | 
   111   | 
    99 // Types (slide)  | 
   112 // Types (slide)  | 
   207   | 
   199   | 
   208 gcd(48, 18)  | 
   200 gcd(48, 18)  | 
   209   | 
   201   | 
   210   | 
   202   | 
   211 def power(x: Int, n: Int) : Int =  | 
   203 def power(x: Int, n: Int) : Int =  | 
   212   if (n == 0) 1  else x * power(x, n - 1)   | 
   204   if (n == 0) 1 else x * power(x, n - 1)   | 
   213   | 
   205   | 
   214 power(5, 5)  | 
   206 power(5, 5)  | 
         | 
   207   | 
         | 
   208   | 
         | 
   209 // Option type  | 
         | 
   210 //=============  | 
         | 
   211   | 
         | 
   212 //in Java if something unusually happens, you return null  | 
         | 
   213 //  | 
         | 
   214 //in Scala you use Option  | 
         | 
   215 //   - if the value is present, you use Some(value)  | 
         | 
   216 //   - if no value is present, you use None  | 
         | 
   217   | 
         | 
   218   | 
         | 
   219 List(7,2,3,4,5,6).find(_ < 4)  | 
         | 
   220 List(5,6,7,8,9).find(_ < 4)  | 
         | 
   221   | 
         | 
   222   | 
         | 
   223   | 
         | 
   224 // error handling with Options (no exceptions)  | 
         | 
   225 //  | 
         | 
   226 //  Try(something).getOrElse(what_to_do_in_case_of_an_exception)  | 
         | 
   227 //  | 
         | 
   228 import scala.util._  | 
         | 
   229 import io.Source  | 
         | 
   230   | 
         | 
   231 val my_url = "https://nms.kcl.ac.uk/christian.urban/"  | 
         | 
   232   | 
         | 
   233 Source.fromURL(my_url).mkString  | 
         | 
   234   | 
         | 
   235 Try(Source.fromURL(my_url).mkString).getOrElse("") | 
         | 
   236   | 
         | 
   237 Try(Some(Source.fromURL(my_url).mkString)).getOrElse(None)  | 
         | 
   238   | 
         | 
   239   | 
         | 
   240 // the same for files  | 
         | 
   241 Source.fromFile("test.txt").mkString | 
   215   | 
   242   | 
   216   | 
   243   | 
   217 // String Interpolations  | 
   244 // String Interpolations  | 
   218 //=======================  | 
   245 //=======================  | 
   219   | 
   246   | 
   269      m <- (1 to 3).toList;  | 
   296      m <- (1 to 3).toList;  | 
   270      if ((n + m) % 2 == 0)) yield (n, m)  | 
   297      if ((n + m) % 2 == 0)) yield (n, m)  | 
   271   | 
   298   | 
   272 // with patterns  | 
   299 // with patterns  | 
   273   | 
   300   | 
   274 for ((m, n) <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield m + n   | 
   301 val lst = List((1, 4), (2, 3), (3, 2), (4, 1))  | 
   275   | 
   302   | 
   276 for (p <- List((1, 4), (2, 3), (3, 2), (4, 1))) yield p._1 + p._2   | 
   303 for ((m, n) <- lst) yield m + n   | 
         | 
   304   | 
         | 
   305 for (p <- lst) yield p._1 + p._2   | 
   277   | 
   306   | 
   278   | 
   307   | 
   279 // general pattern  | 
   308 // general pattern  | 
   280   | 
   309   | 
   281 for (x <- ...) yield { | 
   310 for (x <- ...) yield { | 
   289 // has no "yield"  | 
   318 // has no "yield"  | 
   290   | 
   319   | 
   291 for (n <- (1 to 10)) println(n)  | 
   320 for (n <- (1 to 10)) println(n)  | 
   292   | 
   321   | 
   293   | 
   322   | 
   294   | 
   323 // BTW: a roundabout way of printing out a list, say  | 
   295 // concurrency (ONLY WORKS IN SCALA 2.11.8, not in SCALA 2.12)  | 
   324 val lst = ('a' to 'm').toList | 
   296 //             (would need to have this wrapped into a function, or  | 
   325   | 
   297 //              REPL called with scala -Yrepl-class-based)  | 
   326 for (i <- (0 until lst.length)) println(lst(i))  | 
         | 
   327   | 
         | 
   328 // why not?  | 
         | 
   329 for (c <- lst) println(c)  | 
         | 
   330   | 
         | 
   331 // Aside: concurrency   | 
         | 
   332 // (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12)  | 
         | 
   333 // (would need to have this wrapped into a function, or  | 
         | 
   334 //  REPL called with scala -Yrepl-class-based)  | 
   298 for (n <- (1 to 10)) println(n)  | 
   335 for (n <- (1 to 10)) println(n)  | 
   299 for (n <- (1 to 10).par) println(n)  | 
   336 for (n <- (1 to 10).par) println(n)  | 
   300   | 
   337   | 
   301   | 
   338   | 
   302 // for measuring time  | 
   339 // for measuring time  | 
   311 val list = (1 to 1000000).toList  | 
   348 val list = (1 to 1000000).toList  | 
   312 time_needed(10, for (n <- list) yield n + 42)  | 
   349 time_needed(10, for (n <- list) yield n + 42)  | 
   313 time_needed(10, for (n <- list.par) yield n + 42)  | 
   350 time_needed(10, for (n <- list.par) yield n + 42)  | 
   314   | 
   351   | 
   315   | 
   352   | 
   316 // mutable vs immutable factorial  | 
   353 // Function producing multiple outputs  | 
   317 def fact_mu(n: Long) : Long = { | 
   354 //=====================================  | 
   318   var result : Long = 1  | 
   355   | 
   319   var i = 1  | 
   356 def get_ascii(c: Char) : (Char, Int) = (c, c.toInt)  | 
   320   while (i <= n) { | 
   357   | 
   321     result = result * i  | 
   358 get_ascii('a') | 
   322     i = i + 1  | 
   359   | 
   323   }  | 
   360   | 
   324   result  | 
   361   | 
   325 }  | 
   362 // .maxBy, sortBy with pairs  | 
   326   | 
   363 def get_length(s: String) : (String, Int) = (s, s.length)   | 
   327 def fact_im(num: Long): Long = { | 
   364   | 
   328   if (num == 1) num else  | 
   365 val lst = List("zero", "one", "two", "three", "four", "ten") | 
   329     num * fact_im(num - 1)  | 
   366 val strs = for (s <- lst) yield get_length(s)  | 
   330 }  | 
   367   | 
   331   | 
   368 strs.sortBy(_._2)  | 
   332 def test() = { | 
   369 strs.sortBy(_._1)  | 
   333   for (i <- (0 to 10).par) yield { | 
   370   | 
   334     val l1 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_mu(n)  | 
   371 strs.maxBy(_._2)  | 
   335     val l2 = for (n <- (List.fill(100000)(20 to 21)).flatten.par) yield fact_im(n)   | 
   372 strs.maxBy(_._1)  | 
   336     l1.sum - l2.sum  | 
         | 
   337   }  | 
         | 
   338 }  | 
         | 
   339   | 
         | 
   340 (for (i <- (1 to 10)) yield test().sum).sum  | 
         | 
   341   | 
         | 
   342   | 
         | 
   343 // Webpages  | 
         | 
   344 //==========  | 
         | 
   345   | 
         | 
   346 import io.Source  | 
         | 
   347   | 
         | 
   348 // obtaining a webpage  | 
         | 
   349 val url = """https://nms.kcl.ac.uk/christian.urban/"""   | 
         | 
   350 Source.fromURL(url)("ISO-8859-1").mkString | 
         | 
   351   | 
         | 
   352   | 
         | 
   353 // another example  | 
         | 
   354 //val url = """http://api.postcodes.io/postcodes/CR84LQ"""   | 
         | 
   355   | 
         | 
   356   | 
         | 
   357 // a function for looking up constituency data  | 
         | 
   358 def consty_lookup(pcode: String) : String = { | 
         | 
   359   val url = "http://api.postcodes.io/postcodes/" + pcode  | 
         | 
   360   Source.fromURL(url).mkString.split(",")(16) | 
         | 
   361 }  | 
         | 
   362   | 
         | 
   363 consty_lookup("CR84LQ") | 
         | 
   364 consty_lookup("WC2B4BG") | 
         | 
   365   | 
         | 
   366   | 
         | 
   367 val places =   | 
         | 
   368   List("CR84LQ", "WC2B4BG", "KY169QT", "CB11LY", "CB39AX") | 
         | 
   369   | 
         | 
   370 for (s <- places) println(consty_lookup(s))  | 
         | 
   371   | 
         | 
   372   | 
         | 
   373   | 
         | 
   374   | 
         | 
   375 // A Web Crawler   | 
         | 
   376 //===============  | 
         | 
   377 //  | 
         | 
   378 // the idea is to look for dead links using the  | 
         | 
   379 // regular expression "https?://[^"]*"  | 
         | 
   380   | 
         | 
   381 import io.Source  | 
         | 
   382 import scala.util._  | 
         | 
   383   | 
         | 
   384 // gets the first 10K of a web-page  | 
         | 
   385 def get_page(url: String) : String = { | 
         | 
   386   Try(Source.fromURL(url)("ISO-8859-1").take(10000).mkString). | 
         | 
   387     getOrElse { println(s"  Problem with: $url"); ""} | 
         | 
   388 }  | 
         | 
   389   | 
         | 
   390 // regex for URLs  | 
         | 
   391 val http_pattern = """"https?://[^"]*"""".r  | 
         | 
   392   | 
         | 
   393 // drops the first and last character from a string  | 
         | 
   394 def unquote(s: String) = s.drop(1).dropRight(1)  | 
         | 
   395   | 
         | 
   396 def get_all_URLs(page: String): Set[String] =   | 
         | 
   397   http_pattern.findAllIn(page).map(unquote).toSet  | 
         | 
   398   | 
         | 
   399 // naive version of crawl - searches until a given depth,  | 
         | 
   400 // visits pages potentially more than once  | 
         | 
   401 def crawl(url: String, n: Int) : Unit = { | 
         | 
   402   if (n == 0) ()  | 
         | 
   403   else { | 
         | 
   404     println(s"Visiting: $n $url")  | 
         | 
   405     for (u <- get_all_URLs(get_page(url))) crawl(u, n - 1)  | 
         | 
   406   }  | 
         | 
   407 }  | 
         | 
   408   | 
         | 
   409 // some starting URLs for the crawler  | 
         | 
   410 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""  | 
         | 
   411 //val startURL = """https://nms.kcl.ac.uk/luc.moreau/index.html"""  | 
         | 
   412   | 
         | 
   413 crawl(startURL, 2)  | 
         | 
   414   | 
         | 
   415   | 
         | 
   416   | 
   373   | 
   417 // Further Information  | 
   374 // Further Information  | 
   418 //=====================  | 
   375 //=====================  | 
   419   | 
   376   | 
   420 // The Scala home page and general information is at  | 
   377 // The Scala home page and general information is at  | 
   495   | 
   452   | 
   496   | 
   453   | 
   497   | 
   454   | 
   498   | 
   455   | 
   499   | 
   456   | 
   500 // advantage of case classes  | 
   457   | 
   501 //  | 
   458   | 
   502 case class Participant(name: String, score: Int, active: Boolean)  | 
   459   | 
   503   | 
   460   | 
   504 val ps = Seq(Participant("Jack", 34, true), | 
   461   | 
   505              Participant("Tom", 51, true), | 
   462   | 
   506              Participant("Bob", 90, false)) | 
         | 
   507                | 
         | 
   508 ps.filter(_.score < 50).  | 
         | 
   509    filter(_.active).  | 
         | 
   510    map(_.copy(active = false))  | 
         | 
   511   | 
         | 
   512   | 
         | 
   513   | 
         | 
   514 // another example why state is bad...does not work yet  | 
         | 
   515   | 
         | 
   516 // for measuring time  | 
         | 
   517 def time_needed[T](n: Int, code: => T) = { | 
         | 
   518   val start = System.nanoTime()  | 
         | 
   519   for (i <- (0 to n)) code  | 
         | 
   520   val end = System.nanoTime()  | 
         | 
   521   (end - start) / 1.0e9  | 
         | 
   522 }  | 
         | 
   523   | 
         | 
   524 def santa_state(plan: List[Char]) : Int = {   | 
         | 
   525   | 
         | 
   526   var floor = 0  | 
         | 
   527   | 
         | 
   528   for (i <- plan.par) { | 
         | 
   529     if (i == '(') { | 
         | 
   530       floor += 1  | 
         | 
   531     } else { | 
         | 
   532       floor -= 1  | 
         | 
   533     }  | 
         | 
   534   }  | 
         | 
   535     | 
         | 
   536   floor  | 
         | 
   537 }  | 
         | 
   538   | 
         | 
   539 def i(c: Char) = if (c == '(') 1 else -1 | 
         | 
   540   | 
         | 
   541 def santa_imutable(plan: List[Char]) : Int =  | 
         | 
   542   plan.par.map(i(_)).reduce(_ + _)  | 
         | 
   543   | 
         | 
   544 santa_state("(((((()))))".toList) | 
         | 
   545 santa_imutable("(((((()))))".toList) | 
         | 
   546   | 
         | 
   547 def randomString(length: Int) : String =   | 
         | 
   548   List.fill(length)((40 + scala.util.Random.nextInt(2)).toChar)  | 
         | 
   549   | 
         | 
   550   | 
         | 
   551 santa_state(randomString(100))  | 
         | 
   552   | 
         | 
   553 val large_string = randomString(3000000)  | 
         | 
   554   | 
         | 
   555 time_needed(10, santa_state(large_string))  | 
         | 
   556 time_needed(10, santa_imutable(large_string))  | 
         | 
   557   | 
         | 
   558   | 
         | 
   559   | 
         | 
   560   | 
         | 
   561   | 
         | 
   562 //=======================  | 
         | 
   563 // equality is structural  | 
         | 
   564 val a = "Dave"  | 
         | 
   565 val b = "Dave"  | 
         | 
   566   | 
         | 
   567 if (a == b) println("equal") else println("unequal") | 
         | 
   568   | 
         | 
   569   | 
         | 
   570   | 
         | 
   571 List.fill(10)(math.random)  | 
         | 
   572   | 
         | 
   573 //------------------------  | 
         | 
   574   | 
         | 
   575   | 
         | 
   576 for (a <- 0 to 10) { | 
         | 
   577   println(a)  | 
         | 
   578 }  | 
         | 
   579   | 
         | 
   580 for (a <- 0 until 10) { | 
         | 
   581   println(a)  | 
         | 
   582 }  | 
         | 
   583   | 
         | 
   584 for (a <- 0 until 2; b <- 0 to 2) { | 
         | 
   585     | 
         | 
   586 }  | 
         | 
   587   | 
         | 
   588 output  | 
         | 
   589 a=0, b=0  | 
         | 
   590 a=0, b=1  | 
         | 
   591 a=0, b=2  | 
         | 
   592 a=1, b=0  | 
         | 
   593 a=1, b=1  | 
         | 
   594 a=1, b=2  | 
         |