progs/lecture2.scala
changeset 212 4bda49ec24da
parent 204 9b45dd24271b
child 266 ca48ac1d3c3e
equal deleted inserted replaced
211:092e0879a5ae 212:4bda49ec24da
    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 
    21 // (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12)
    22 // Just for "Fun": Mutable vs Immutable
    22 // (would need to have this wrapped into a function, or
    23 //=======================================
    23 //  REPL called with scala -Yrepl-class-based)
       
    24 
       
    25 
       
    26 // Just for Fun: Mutable vs Immutable
       
    27 //====================================
    24 //
    28 //
    25 // - no vars, no ++i, no +=
    29 // - no vars, no ++i, no +=
    26 // - no mutable data-structures (no Arrays, no ListBuffers)
    30 // - no mutable data-structures (no Arrays, no ListBuffers)
    27 
    31 
    28 
    32 
    29 // Q: Count how many elements are in the intersections of two sets?
    33 // Q: Count how many elements are in the intersections of 
       
    34 //    two sets?
    30 
    35 
    31 def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
    36 def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
    32   var count = 0
    37   var count = 0
    33   for (x <- A; if B contains x) count += 1 
    38   for (x <- A; if B contains x) count += 1 
    34   count
    39   count
    82 lst.filter(even(_))
    87 lst.filter(even(_))
    83 lst.filter(even)
    88 lst.filter(even)
    84 
    89 
    85 lst.count(even)
    90 lst.count(even)
    86 
    91 
    87 lst.find(_ > 8)
    92 
    88 
    93 lst.find(even)
    89 
    94 
    90 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 1), (1, 0))
    95 val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0))
       
    96 
       
    97 lst.sortWith(_ > _)
       
    98 lst.sortWith(_ < _)
       
    99 
       
   100 def lex(x: (Int, Int), y: (Int, Int)) : Boolean = 
       
   101   if (x._1 == y._1) x._2 < y._2 else x._1 < y._1
       
   102 
       
   103 ps.sortWith(lex)
    91 
   104 
    92 ps.sortBy(_._1)
   105 ps.sortBy(_._1)
    93 ps.sortBy(_._2)
   106 ps.sortBy(_._2)
    94 
   107 
    95 ps.maxBy(_._1)
   108 ps.maxBy(_._1)
    96 ps.maxBy(_._2)
   109 ps.maxBy(_._2)
    97 
   110 
    98 
   111 
    99 
   112 
   100 // maps
   113 // maps (lower-case)
   101 //=====
   114 //===================
   102 
   115 
       
   116 def double(x: Int): Int = x + x
   103 def square(x: Int): Int = x * x
   117 def square(x: Int): Int = x * x
   104 
   118 
       
   119 
       
   120 
   105 val lst = (1 to 10).toList
   121 val lst = (1 to 10).toList
       
   122 
       
   123 lst.map(x => (double(x), square(x)))
   106 
   124 
   107 lst.map(square)
   125 lst.map(square)
   108 
   126 
   109 // this is actually what for is defined at in Scala
   127 // this is actually what for is defined at in Scala
   110 
   128 
   118 lst.map(square).filter(_ > 4).map(square)
   136 lst.map(square).filter(_ > 4).map(square)
   119 
   137 
   120 
   138 
   121 // lets define our own functions
   139 // lets define our own functions
   122 // type of functions, for example f: Int => Int
   140 // type of functions, for example f: Int => Int
       
   141 
       
   142 lst.tail
   123 
   143 
   124 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = {
   144 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = {
   125   if (lst == Nil) Nil
   145   if (lst == Nil) Nil
   126   else f(lst.head) :: my_map_int(lst.tail, f)
   146   else f(lst.head) :: my_map_int(lst.tail, f)
   127 }
   147 }
   141 // other function types
   161 // other function types
   142 //
   162 //
   143 // f1: (Int, Int) => Int
   163 // f1: (Int, Int) => Int
   144 // f2: List[String] => Option[Int]
   164 // f2: List[String] => Option[Int]
   145 // ... 
   165 // ... 
   146 
   166 val lst = (1 to 10).toList
   147 
   167 
   148 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
   168 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
   149   case Nil => 0
   169   case Nil => 0
   150   case x::xs => f(x) + sumOf(f, xs)
   170   case x::xs => f(x) + sumOf(f, xs)
   151 }
   171 }
   155 
   175 
   156 sum_squares(lst)
   176 sum_squares(lst)
   157 sum_cubes(lst)
   177 sum_cubes(lst)
   158 
   178 
   159 // lets try it factorial
   179 // lets try it factorial
   160 def fact(n: Int) : Int = ...
   180 def fact(n: Int) : Int = 
       
   181   if (n == 0) 1 else n * fact(n - 1)
   161 
   182 
   162 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
   183 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
   163 sum_fact(lst)
   184 sum_fact(lst)
   164 
   185 
   165 
   186 
   166 
   187 
   167 
   188 
   168 
   189 
   169 // Map type
   190 // Map type (upper-case)
   170 //==========
   191 //=======================
   171 
   192 
   172 // Note the difference between map and Map
   193 // Note the difference between map and Map
   173 
   194 
   174 def factors(n: Int) : List[Int] =
   195 def factors(n: Int) : List[Int] =
   175   ((1 until n).filter { divisor =>
   196   ((1 until n).filter { divisor =>
   186 // works for lists of pairs
   207 // works for lists of pairs
   187 facs.toMap
   208 facs.toMap
   188 
   209 
   189 
   210 
   190 facs.toMap.get(4)
   211 facs.toMap.get(4)
   191 facs.toMap.getOrElse(4, Nil)
   212 facs.toMap.getOrElse(42, Nil)
   192 
   213 
   193 val facsMap = facs.toMap
   214 val facsMap = facs.toMap
   194 
   215 
   195 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5))
   216 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5))
   196 facsMap0.get(0)
   217 facsMap0.get(1)
   197 
   218 
   198 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5))
   219 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5))
   199 facsMap.get(1)
   220 facsMap.get(1)
   200 facsMap4.get(1)
   221 facsMap4.get(1)
   201 
   222 
   202 val ls = List("one", "two", "three", "four", "five")
   223 val ls = List("one", "two", "three", "four", "five")
   203 ls.groupBy(_.length)
   224 ls.groupBy(_.length)
   204 
   225 
   205 ls.groupBy(_.length).get(3)
   226 ls.groupBy(_.length).get(2)
   206 
   227 
   207 
   228 
   208 
   229 
   209 // Option type
   230 // Option type
   210 //=============
   231 //=============
   224 val lst = List(None, Some(1), Some(2), None, Some(3))
   245 val lst = List(None, Some(1), Some(2), None, Some(3))
   225 
   246 
   226 lst.flatten
   247 lst.flatten
   227 
   248 
   228 Some(1).get
   249 Some(1).get
       
   250 None.get
   229 
   251 
   230 Some(1).isDefined
   252 Some(1).isDefined
       
   253 None.isDefined
       
   254 
       
   255 
   231 None.isDefined
   256 None.isDefined
   232 
   257 
   233 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
   258 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
   234 
   259 
   235 for ((x, y) <- ps) yield {
   260 for ((x, y) <- ps) yield {
   250 //  Try(something).getOrElse(what_to_do_in_an_exception)
   275 //  Try(something).getOrElse(what_to_do_in_an_exception)
   251 //
   276 //
   252 import scala.util._
   277 import scala.util._
   253 import io.Source
   278 import io.Source
   254 
   279 
   255 Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString
   280 
       
   281 Source.fromURL("""http://www.inf.ucl.ac.uk/staff/urbanc/""").mkString
   256 
   282 
   257 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
   283 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
   258 
   284 
   259 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None)
   285 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None)
   260 
   286 
   261 
   287 
   262 // a function that turns strings into numbers (similar to .toInt)
   288 // a function that turns strings into numbers (similar to .toInt)
   263 Integer.parseInt("1234")
   289 Integer.parseInt("12u34")
   264 
   290 
   265 
   291 
   266 def get_me_an_int(s: String) : Option[Int] = 
   292 def get_me_an_int(s: String) : Option[Int] = 
   267  Try(Some(Integer.parseInt(s))).getOrElse(None)
   293  Try(Some(Integer.parseInt(s))).getOrElse(None)
   268 
   294 
   269 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
   295 val lst = List("12345", "foo", "5432", "bar", "x21", "456")
   270 for (x <- lst) yield get_me_an_int(x)
   296 for (x <- lst) yield get_me_an_int(x)
   271 
   297 
   272 // summing all the numbers
   298 // summing all the numbers
   273 
   299 
   274 lst.map(get_me_an_int)
       
   275 lst.map(get_me_an_int).flatten.sum
   300 lst.map(get_me_an_int).flatten.sum
   276 
   301 lst.map(get_me_an_int).flatten.sum
   277 
   302 
   278 val sum = lst.flatMap(get_me_an_int).sum
   303 
       
   304 lst.flatMap(get_me_an_int).map(_.toString)
   279 
   305 
   280 
   306 
   281 // This may not look any better than working with null in Java, but to
   307 // This may not look any better than working with null in Java, but to
   282 // see the value, you have to put yourself in the shoes of the
   308 // see the value, you have to put yourself in the shoes of the
   283 // consumer of the get_me_an_int function, and imagine you didn't
   309 // consumer of the get_me_an_int function, and imagine you didn't
   292 
   318 
   293 // even Scala is not immune to problems like this:
   319 // even Scala is not immune to problems like this:
   294 
   320 
   295 List(5,6,7,8,9).indexOf(7)
   321 List(5,6,7,8,9).indexOf(7)
   296 List(5,6,7,8,9).indexOf(10)
   322 List(5,6,7,8,9).indexOf(10)
   297 
   323 List(5,6,7,8,9)(-1)
   298 
   324 
   299 
   325 
   300 
   326 
   301 // Pattern Matching
   327 // Pattern Matching
   302 //==================
   328 //==================
   319 
   345 
   320 // remember?
   346 // remember?
   321 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten
   347 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten
   322 
   348 
   323 
   349 
   324 def my_flatten(xs: List[Option[Int]]): List[Int] = {
   350 def my_flatten(xs: List[Option[Int]]): List[Int] = xs match {
   325   ...
   351   case Nil => Nil 
   326 }
   352   case None::rest => my_flatten(rest)
   327 
   353   case Some(v)::foo => {
   328 
   354       v :: my_flatten(foo)
   329 
   355   } 
   330 def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
       
   331   case Nil => Nil
       
   332   case None::xs => my_flatten(xs)
       
   333   case Some(n)::xs => n::my_flatten(xs)
       
   334 }
   356 }
   335 
   357 
   336 
   358 
   337 // another example
   359 // another example
   338 def get_me_a_string(n: Int): String = n match {
   360 def get_me_a_string(n: Int): String = n match {
   339   case 0 => "zero"
   361   case 0 | 1 | 2 => "small"
   340   case 1 => "one"
   362   case _ => "big"
   341   case 2 => "two"
       
   342   case _ => "many"
       
   343 }
   363 }
   344 
   364 
   345 get_me_a_string(0)
   365 get_me_a_string(0)
       
   366 
   346 
   367 
   347 // you can also have cases combined
   368 // you can also have cases combined
   348 def season(month: String) = month match {
   369 def season(month: String) = month match {
   349   case "March" | "April" | "May" => "It's spring"
   370   case "March" | "April" | "May" => "It's spring"
   350   case "June" | "July" | "August" => "It's summer"
   371   case "June" | "July" | "August" => "It's summer"
   354 }
   375 }
   355  
   376  
   356 println(season("November"))
   377 println(season("November"))
   357 
   378 
   358 // What happens if no case matches?
   379 // What happens if no case matches?
   359 
       
   360 println(season("foobar"))
   380 println(season("foobar"))
       
   381 
   361 
   382 
   362 // Silly: fizz buzz
   383 // Silly: fizz buzz
   363 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match {
   384 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match {
   364   case (0, 0) => "fizz buzz"
   385   case (0, 0) => "fizz buzz"
   365   case (0, _) => "fizz"
   386   case (0, _) => "fizz"
   399 case object C extends RomanDigit 
   420 case object C extends RomanDigit 
   400 case object D extends RomanDigit 
   421 case object D extends RomanDigit 
   401 case object M extends RomanDigit 
   422 case object M extends RomanDigit 
   402 
   423 
   403 type RomanNumeral = List[RomanDigit] 
   424 type RomanNumeral = List[RomanDigit] 
       
   425 
       
   426 List(X,I)
       
   427 
       
   428 I -> 1
       
   429 II -> 2
       
   430 III  -> 3
       
   431 IV -> 4
       
   432 V -> 5
       
   433 VI -> 6
       
   434 VII -> 7
       
   435 VIII -> 8
       
   436 IX -> 9
       
   437 X -> X
   404 
   438 
   405 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
   439 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
   406   case Nil => 0
   440   case Nil => 0
   407   case M::r    => 1000 + RomanNumeral2Int(r)  
   441   case M::r    => 1000 + RomanNumeral2Int(r)  
   408   case C::M::r => 900 + RomanNumeral2Int(r)
   442   case C::M::r => 900 + RomanNumeral2Int(r)
   428 
   462 
   429 
   463 
   430 // another example
   464 // another example
   431 //=================
   465 //=================
   432 
   466 
   433 // Once upon a time, in a complete fictional country there were Persons...
   467 // Once upon a time, in a complete fictional 
       
   468 // country there were Persons...
   434 
   469 
   435 
   470 
   436 abstract class Person
   471 abstract class Person
   437 case object King extends Person
   472 case object King extends Person
   438 case class Peer(deg: String, terr: String, succ: Int) extends Person
   473 case class Peer(deg: String, terr: String, succ: Int) extends Person
   439 case class Knight(name: String) extends Person
   474 case class Knight(name: String) extends Person
   440 case class Peasant(name: String) extends Person
   475 case class Peasant(name: String) extends Person
   441 case object Clown extends Person
   476 
   442 
   477 
   443 def title(p: Person): String = p match {
   478 def title(p: Person): String = p match {
   444   case King => "His Majesty the King"
   479   case King => "His Majesty the King"
   445   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
   480   case Peer(deg, terr, _) => s"The ${deg} of ${terr}"
   446   case Knight(name) => s"Sir ${name}"
   481   case Knight(name) => s"Sir ${name}"
   462                   Peer("Duke", "Norfolk", 84), 
   497                   Peer("Duke", "Norfolk", 84), 
   463                   Peasant("Christian"), 
   498                   Peasant("Christian"), 
   464                   King, 
   499                   King, 
   465                   Clown)
   500                   Clown)
   466 
   501 
   467 println(people.sortWith(superior(_, _)).mkString(", "))
   502 println(people.sortWith(superior).mkString("\n"))
       
   503 
       
   504 print("123\\n456")
   468 
   505 
   469 
   506 
   470 // Tail recursion
   507 // Tail recursion
   471 //================
   508 //================
   472 
   509 
   497 // to allocate stack-space in each recursive
   534 // to allocate stack-space in each recursive
   498 // call; Scala can do this only for tail-recursive
   535 // call; Scala can do this only for tail-recursive
   499 // functions
   536 // functions
   500 
   537 
   501 
   538 
   502 // A Web Crawler 
   539 // A Web Crawler / Email Harvester
   503 //===============
   540 //=================================
   504 //
   541 //
   505 // the idea is to look for dead links using the
   542 // the idea is to look for links using the
   506 // regular expression "https?://[^"]*"
   543 // regular expression "https?://[^"]*" and for
       
   544 // email addresses using another regex.
   507 
   545 
   508 import io.Source
   546 import io.Source
   509 import scala.util._
   547 import scala.util._
   510 
   548 
   511 // gets the first 10K of a web-page
   549 // gets the first 10K of a web-page
   515 }
   553 }
   516 
   554 
   517 // regex for URLs and emails
   555 // regex for URLs and emails
   518 val http_pattern = """"https?://[^"]*"""".r
   556 val http_pattern = """"https?://[^"]*"""".r
   519 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r
   557 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r
       
   558 
       
   559 //email_pattern.findAllIn
       
   560 //  ("foo bla christian@kcl.ac.uk 1234567").toList
   520 
   561 
   521 
   562 
   522 // drops the first and last character from a string
   563 // drops the first and last character from a string
   523 def unquote(s: String) = s.drop(1).dropRight(1)
   564 def unquote(s: String) = s.drop(1).dropRight(1)
   524 
   565 
   531   if (n == 0) Set()
   572   if (n == 0) Set()
   532   else {
   573   else {
   533     println(s"  Visiting: $n $url")
   574     println(s"  Visiting: $n $url")
   534     val page = get_page(url)
   575     val page = get_page(url)
   535     val new_emails = email_pattern.findAllIn(page).toSet
   576     val new_emails = email_pattern.findAllIn(page).toSet
   536     new_emails ++ (for (u <- get_all_URLs(page).par) yield crawl(u, n - 1)).flatten
   577     new_emails ++ (for (u <- get_all_URLs(page)) yield crawl(u, n - 1)).flatten
   537   }
   578   }
   538 }
   579 }
   539 
   580 
   540 // some starting URLs for the crawler
   581 // some starting URLs for the crawler
   541 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""
   582 val startURL = """https://nms.kcl.ac.uk/christian.urban/"""