diff -r 092e0879a5ae -r 4bda49ec24da progs/lecture2.scala --- 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 } }