--- 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
}
}