--- a/progs/lecture2.scala Tue Nov 12 00:41:00 2019 +0000
+++ b/progs/lecture2.scala Tue Nov 12 10:47:27 2019 +0000
@@ -75,11 +75,14 @@
// the same for files
Try(Some(Source.fromFile("text.txt").mkString)).getOrElse(None)
-// how to implement a function for reading something from files...
+// how to implement a function for reading
+// (lines) something from files...
+//
def get_contents(name: String) : List[String] =
Source.fromFile(name).getLines.toList
+get_contents("text.txt")
get_contents("test.txt")
// slightly better - return Nil
@@ -156,6 +159,7 @@
//========================
// functions can take functions as arguments
+// and produce functions as result
def even(x: Int) : Boolean = x % 2 == 0
def odd(x: Int) : Boolean = x % 2 == 1
@@ -204,8 +208,8 @@
lst.map(square)
-// this is actually how for-comprehensions
-// defined as in Scala
+// this is actually how for-comprehensions are
+// defined in Scala
lst.map(n => square(n))
for (n <- lst) yield square(n)
@@ -232,7 +236,8 @@
// same function using pattern matching: a kind
// of switch statement on steroids (see more later on)
-def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = lst match {
+def my_map_int(lst: List[Int], f: Int => Int) : List[Int] =
+lst match {
case Nil => Nil
case x::xs => f(x)::my_map_int(xs, f)
}
@@ -268,10 +273,10 @@
// sometimes it is needed that you specify the type.
(1 to 100).filter((x: Int) => x % 2 == 0).sum
-// in this case it is clear that x mist be an Int
+// in this case it is clear that x must be an Int
(1 to 100).filter(x => x % 2 == 0).sum
-// As each parameter (only x in this case) is passed only once
+// When each parameter (only x in this case) is used only once
// you can use the wizardy placeholder syntax
(1 to 100).filter(_ % 2 == 0).sum
@@ -334,7 +339,7 @@
facsMap.get(1)
facsMap2.get(1)
-// groupBy function on maps
+// groupBy function on Maps
val ls = List("one", "two", "three", "four", "five")
ls.groupBy(_.length)
@@ -361,18 +366,17 @@
// }
-
-
-// remember?
+// recall
val lst = List(None, Some(1), Some(2), None, Some(3)).flatten
-
def my_flatten(xs: List[Option[Int]]): List[Int] = xs match {
case Nil => Nil
case None::rest => my_flatten(rest)
case Some(v)::rest => v :: my_flatten(rest)
}
+my_flatten(List(None, Some(1), Some(2), None, Some(3)))
+
// another example with a default case
def get_me_a_string(n: Int): String = n match {
@@ -538,4 +542,73 @@
+// Jumping Towers
+//================
+
+def moves(xs: List[Int], n: Int) : List[List[Int]] = (xs, n) match {
+ case (Nil, _) => Nil
+ case (xs, 0) => Nil
+ case (x::xs, n) => (x::xs) :: moves(xs, n - 1)
+}
+
+
+moves(List(5,1,0), 1)
+moves(List(5,1,0), 2)
+moves(List(5,1,0), 5)
+
+// checks whether a jump tour exists at all
+
+def search(xs: List[Int]) : Boolean = xs match {
+ case Nil => true
+ case (x::xs) =>
+ if (xs.length < x) true else moves(xs, x).exists(search(_))
+}
+
+
+search(List(5,3,2,5,1,1))
+search(List(3,5,1,0,0,0,1))
+search(List(3,5,1,0,0,0,0,1))
+search(List(3,5,1,0,0,0,1,1))
+search(List(3,5,1))
+search(List(5,1,1))
+search(Nil)
+search(List(1))
+search(List(5,1,1))
+search(List(3,5,1,0,0,0,0,0,0,0,0,1))
+
+// generate *all* jump tours
+// if we are only interested in the shortes one, we could
+// shortcircut the calculation and only return List(x) in
+// case where xs.length < x, because no tour can be shorter
+// than 1
+//
+
+def jumps(xs: List[Int]) : List[List[Int]] = xs match {
+ case Nil => Nil
+ case (x::xs) => {
+ val children = moves(xs, x)
+ val results = children.map(cs => jumps(cs).map(x :: _)).flatten
+ if (xs.length < x) List(x) :: results else results
+ }
+}
+
+jumps(List(3,5,1,2,1,2,1))
+jumps(List(3,5,1,2,3,4,1))
+jumps(List(3,5,1,0,0,0,1))
+jumps(List(3,5,1))
+jumps(List(5,1,1))
+jumps(Nil)
+jumps(List(1))
+jumps(List(5,1,2))
+moves(List(1,2), 5)
+jumps(List(1,5,1,2))
+jumps(List(3,5,1,0,0,0,0,0,0,0,0,1))
+
+jumps(List(5,3,2,5,1,1)).minBy(_.length)
+jumps(List(1,3,5,8,9,2,6,7,6,8,9)).minBy(_.length)
+jumps(List(1,3,6,1,0,9)).minBy(_.length)
+jumps(List(2,3,1,1,2,4,2,0,1,1)).minBy(_.length)
+
+
+