progs/lecture2.scala
changeset 212 4bda49ec24da
parent 204 9b45dd24271b
child 266 ca48ac1d3c3e
--- a/progs/lecture2.scala	Tue Nov 20 13:42:32 2018 +0000
+++ b/progs/lecture2.scala	Tue Nov 20 14:31:14 2018 +0000
@@ -18,15 +18,20 @@
 time_needed(10, for (n <- list) yield n + 42)
 time_needed(10, for (n <- list.par) yield n + 42)
 
+// (ONLY WORKS OUT-OF-THE-BOX IN SCALA 2.11.8, not in SCALA 2.12)
+// (would need to have this wrapped into a function, or
+//  REPL called with scala -Yrepl-class-based)
 
-// Just for "Fun": Mutable vs Immutable
-//=======================================
+
+// Just for Fun: Mutable vs Immutable
+//====================================
 //
 // - no vars, no ++i, no +=
 // - no mutable data-structures (no Arrays, no ListBuffers)
 
 
-// Q: Count how many elements are in the intersections of two sets?
+// Q: Count how many elements are in the intersections of 
+//    two sets?
 
 def count_intersection(A: Set[Int], B: Set[Int]) : Int = {
   var count = 0
@@ -84,10 +89,18 @@
 
 lst.count(even)
 
-lst.find(_ > 8)
+
+lst.find(even)
+
+val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0))
 
+lst.sortWith(_ > _)
+lst.sortWith(_ < _)
 
-val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 1), (1, 0))
+def lex(x: (Int, Int), y: (Int, Int)) : Boolean = 
+  if (x._1 == y._1) x._2 < y._2 else x._1 < y._1
+
+ps.sortWith(lex)
 
 ps.sortBy(_._1)
 ps.sortBy(_._2)
@@ -97,13 +110,18 @@
 
 
 
-// maps
-//=====
+// maps (lower-case)
+//===================
 
+def double(x: Int): Int = x + x
 def square(x: Int): Int = x * x
 
+
+
 val lst = (1 to 10).toList
 
+lst.map(x => (double(x), square(x)))
+
 lst.map(square)
 
 // this is actually what for is defined at in Scala
@@ -121,6 +139,8 @@
 // lets define our own functions
 // type of functions, for example f: Int => Int
 
+lst.tail
+
 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = {
   if (lst == Nil) Nil
   else f(lst.head) :: my_map_int(lst.tail, f)
@@ -143,7 +163,7 @@
 // f1: (Int, Int) => Int
 // f2: List[String] => Option[Int]
 // ... 
-
+val lst = (1 to 10).toList
 
 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match {
   case Nil => 0
@@ -157,7 +177,8 @@
 sum_cubes(lst)
 
 // lets try it factorial
-def fact(n: Int) : Int = ...
+def fact(n: Int) : Int = 
+  if (n == 0) 1 else n * fact(n - 1)
 
 def sum_fact(lst: List[Int]) = sumOf(fact, lst)
 sum_fact(lst)
@@ -166,8 +187,8 @@
 
 
 
-// Map type
-//==========
+// Map type (upper-case)
+//=======================
 
 // Note the difference between map and Map
 
@@ -188,12 +209,12 @@
 
 
 facs.toMap.get(4)
-facs.toMap.getOrElse(4, Nil)
+facs.toMap.getOrElse(42, Nil)
 
 val facsMap = facs.toMap
 
 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5))
-facsMap0.get(0)
+facsMap0.get(1)
 
 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5))
 facsMap.get(1)
@@ -202,7 +223,7 @@
 val ls = List("one", "two", "three", "four", "five")
 ls.groupBy(_.length)
 
-ls.groupBy(_.length).get(3)
+ls.groupBy(_.length).get(2)
 
 
 
@@ -226,10 +247,14 @@
 lst.flatten
 
 Some(1).get
+None.get
 
 Some(1).isDefined
 None.isDefined
 
+
+None.isDefined
+
 val ps = List((3, 0), (3, 2), (4, 2), (2, 0), (1, 0), (1, 1))
 
 for ((x, y) <- ps) yield {
@@ -252,7 +277,8 @@
 import scala.util._
 import io.Source
 
-Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString
+
+Source.fromURL("""http://www.inf.ucl.ac.uk/staff/urbanc/""").mkString
 
 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("")
 
@@ -260,7 +286,7 @@
 
 
 // a function that turns strings into numbers (similar to .toInt)
-Integer.parseInt("1234")
+Integer.parseInt("12u34")
 
 
 def get_me_an_int(s: String) : Option[Int] = 
@@ -271,11 +297,11 @@
 
 // summing all the numbers
 
-lst.map(get_me_an_int)
+lst.map(get_me_an_int).flatten.sum
 lst.map(get_me_an_int).flatten.sum
 
 
-val sum = lst.flatMap(get_me_an_int).sum
+lst.flatMap(get_me_an_int).map(_.toString)
 
 
 // This may not look any better than working with null in Java, but to
@@ -294,7 +320,7 @@
 
 List(5,6,7,8,9).indexOf(7)
 List(5,6,7,8,9).indexOf(10)
-
+List(5,6,7,8,9)(-1)
 
 
 
@@ -321,29 +347,24 @@
 val lst = List(None, Some(1), Some(2), None, Some(3)).flatten
 
 
-def my_flatten(xs: List[Option[Int]]): List[Int] = {
-  ...
-}
-
-
-
-def my_flatten(lst: List[Option[Int]]): List[Int] = lst match {
-  case Nil => Nil
-  case None::xs => my_flatten(xs)
-  case Some(n)::xs => n::my_flatten(xs)
+def my_flatten(xs: List[Option[Int]]): List[Int] = xs match {
+  case Nil => Nil 
+  case None::rest => my_flatten(rest)
+  case Some(v)::foo => {
+      v :: my_flatten(foo)
+  } 
 }
 
 
 // another example
 def get_me_a_string(n: Int): String = n match {
-  case 0 => "zero"
-  case 1 => "one"
-  case 2 => "two"
-  case _ => "many"
+  case 0 | 1 | 2 => "small"
+  case _ => "big"
 }
 
 get_me_a_string(0)
 
+
 // you can also have cases combined
 def season(month: String) = month match {
   case "March" | "April" | "May" => "It's spring"
@@ -356,8 +377,8 @@
 println(season("November"))
 
 // What happens if no case matches?
+println(season("foobar"))
 
-println(season("foobar"))
 
 // Silly: fizz buzz
 def fizz_buzz(n: Int) : String = (n % 3, n % 5) match {
@@ -402,6 +423,19 @@
 
 type RomanNumeral = List[RomanDigit] 
 
+List(X,I)
+
+I -> 1
+II -> 2
+III  -> 3
+IV -> 4
+V -> 5
+VI -> 6
+VII -> 7
+VIII -> 8
+IX -> 9
+X -> X
+
 def RomanNumeral2Int(rs: RomanNumeral): Int = rs match { 
   case Nil => 0
   case M::r    => 1000 + RomanNumeral2Int(r)  
@@ -430,7 +464,8 @@
 // another example
 //=================
 
-// Once upon a time, in a complete fictional country there were Persons...
+// Once upon a time, in a complete fictional 
+// country there were Persons...
 
 
 abstract class Person
@@ -438,7 +473,7 @@
 case class Peer(deg: String, terr: String, succ: Int) extends Person
 case class Knight(name: String) extends Person
 case class Peasant(name: String) extends Person
-case object Clown extends Person
+
 
 def title(p: Person): String = p match {
   case King => "His Majesty the King"
@@ -464,7 +499,9 @@
                   King, 
                   Clown)
 
-println(people.sortWith(superior(_, _)).mkString(", "))
+println(people.sortWith(superior).mkString("\n"))
+
+print("123\\n456")
 
 
 // Tail recursion
@@ -499,11 +536,12 @@
 // functions
 
 
-// A Web Crawler 
-//===============
+// A Web Crawler / Email Harvester
+//=================================
 //
-// the idea is to look for dead links using the
-// regular expression "https?://[^"]*"
+// the idea is to look for links using the
+// regular expression "https?://[^"]*" and for
+// email addresses using another regex.
 
 import io.Source
 import scala.util._
@@ -518,6 +556,9 @@
 val http_pattern = """"https?://[^"]*"""".r
 val email_pattern = """([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})""".r
 
+//email_pattern.findAllIn
+//  ("foo bla christian@kcl.ac.uk 1234567").toList
+
 
 // drops the first and last character from a string
 def unquote(s: String) = s.drop(1).dropRight(1)
@@ -533,7 +574,7 @@
     println(s"  Visiting: $n $url")
     val page = get_page(url)
     val new_emails = email_pattern.findAllIn(page).toSet
-    new_emails ++ (for (u <- get_all_URLs(page).par) yield crawl(u, n - 1)).flatten
+    new_emails ++ (for (u <- get_all_URLs(page)) yield crawl(u, n - 1)).flatten
   }
 }