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/""" |