59 get_contents("text.txt") |
91 get_contents("text.txt") |
60 get_contents("test.txt") |
92 get_contents("test.txt") |
61 |
93 |
62 |
94 |
63 |
95 |
64 // For-Comprehensions Again |
|
65 //========================== |
|
66 |
|
67 // the first produces a result, while the second does not |
|
68 for (n <- List(1, 2, 3, 4, 5)) yield n * n |
|
69 |
|
70 |
|
71 for (n <- List(1, 2, 3, 4, 5)) println(n) |
|
72 |
|
73 |
|
74 // String Interpolations |
|
75 //======================= |
|
76 |
|
77 val n = 3 |
|
78 println("The square of " + n + " is " + square(n) + ".") |
|
79 |
|
80 println(s"The square of ${n} is ${square(n)}.") |
|
81 |
|
82 |
|
83 // helpful for debugging purposes |
|
84 // |
|
85 // "The most effective debugging tool is still careful thought, |
|
86 // coupled with judiciously placed print statements." |
|
87 // — Brian W. Kernighan, in Unix for Beginners (1979) |
|
88 |
|
89 |
|
90 def gcd_db(a: Int, b: Int) : Int = { |
|
91 println(s"Function called with ${a} and ${b}.") |
|
92 if (b == 0) a else gcd_db(b, a % b) |
|
93 } |
|
94 |
|
95 gcd_db(48, 18) |
|
96 |
|
97 |
|
98 // Asserts/Testing |
|
99 //================= |
|
100 |
|
101 assert(gcd(48, 18) == 6) |
|
102 |
|
103 assert(gcd(48, 18) == 5, "The gcd test failed") |
|
104 |
|
105 |
|
106 |
|
107 // Higher-Order Functions |
|
108 //======================== |
|
109 |
|
110 // functions can take functions as arguments |
|
111 |
|
112 def even(x: Int) : Boolean = x % 2 == 0 |
|
113 def odd(x: Int) : Boolean = x % 2 == 1 |
|
114 |
|
115 val lst = (1 to 10).toList |
|
116 |
|
117 lst.filter(x => even(x)) |
|
118 lst.filter(even(_)) |
|
119 lst.filter(even) |
|
120 |
|
121 lst.count(even) |
|
122 |
|
123 |
|
124 lst.find(even) |
|
125 |
|
126 val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0)) |
|
127 |
|
128 lst.sortWith(_ > _) |
|
129 lst.sortWith(_ < _) |
|
130 |
|
131 def lex(x: (Int, Int), y: (Int, Int)) : Boolean = |
|
132 if (x._1 == y._1) x._2 < y._2 else x._1 < y._1 |
|
133 |
|
134 ps.sortWith(lex) |
|
135 |
|
136 ps.sortBy(_._1) |
|
137 ps.sortBy(_._2) |
|
138 |
|
139 ps.maxBy(_._1) |
|
140 ps.maxBy(_._2) |
|
141 |
|
142 |
|
143 |
|
144 // maps (lower-case) |
|
145 //=================== |
|
146 |
|
147 def double(x: Int): Int = x + x |
|
148 def square(x: Int): Int = x * x |
|
149 |
|
150 |
|
151 |
|
152 val lst = (1 to 10).toList |
|
153 |
|
154 lst.map(x => (double(x), square(x))) |
|
155 |
|
156 lst.map(square) |
|
157 |
|
158 // this is actually how for-comprehensions |
|
159 // defined as in Scala |
|
160 |
|
161 lst.map(n => square(n)) |
|
162 for (n <- lst) yield square(n) |
|
163 |
|
164 // this can be iterated |
|
165 |
|
166 lst.map(square).filter(_ > 4) |
|
167 |
|
168 lst.map(square).filter(_ > 4).map(square) |
|
169 |
|
170 |
|
171 // lets define our own functions |
|
172 // type of functions, for example f: Int => Int |
|
173 |
|
174 lst.tail |
|
175 |
|
176 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = { |
|
177 if (lst == Nil) Nil |
|
178 else f(lst.head) :: my_map_int(lst.tail, f) |
|
179 } |
|
180 |
|
181 my_map_int(lst, square) |
|
182 |
|
183 |
|
184 // same function using pattern matching: a kind |
|
185 // of switch statement on steroids (see more later on) |
|
186 |
|
187 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = lst match { |
|
188 case Nil => Nil |
|
189 case x::xs => f(x)::my_map_int(xs, f) |
|
190 } |
|
191 |
|
192 |
|
193 // other function types |
|
194 // |
|
195 // f1: (Int, Int) => Int |
|
196 // f2: List[String] => Option[Int] |
|
197 // ... |
|
198 val lst = (1 to 10).toList |
|
199 |
|
200 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
|
201 case Nil => 0 |
|
202 case x::xs => f(x) + sumOf(f, xs) |
|
203 } |
|
204 |
|
205 def sum_squares(lst: List[Int]) = sumOf(square, lst) |
|
206 def sum_cubes(lst: List[Int]) = sumOf(x => x * x * x, lst) |
|
207 |
|
208 sum_squares(lst) |
|
209 sum_cubes(lst) |
|
210 |
|
211 // lets try it factorial |
|
212 def fact(n: Int) : Int = |
|
213 if (n == 0) 1 else n * fact(n - 1) |
|
214 |
|
215 def sum_fact(lst: List[Int]) = sumOf(fact, lst) |
|
216 sum_fact(lst) |
|
217 |
|
218 |
|
219 |
|
220 |
|
221 |
|
222 // Map type (upper-case) |
|
223 //======================= |
|
224 |
|
225 // Note the difference between map and Map |
|
226 |
|
227 def factors(n: Int) : List[Int] = |
|
228 ((1 until n).filter { divisor => |
|
229 n % divisor == 0 |
|
230 }).toList |
|
231 |
|
232 |
|
233 var ls = (1 to 10).toList |
|
234 |
|
235 val facs = ls.map(n => (n, factors(n))) |
|
236 |
|
237 facs.find(_._1 == 4) |
|
238 |
|
239 // works for lists of pairs |
|
240 facs.toMap |
|
241 |
|
242 |
|
243 facs.toMap.get(4) |
|
244 facs.toMap.getOrElse(42, Nil) |
|
245 |
|
246 val facsMap = facs.toMap |
|
247 |
|
248 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5)) |
|
249 facsMap0.get(1) |
|
250 |
|
251 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5)) |
|
252 facsMap.get(1) |
|
253 facsMap4.get(1) |
|
254 |
|
255 val ls = List("one", "two", "three", "four", "five") |
|
256 ls.groupBy(_.length) |
|
257 |
|
258 ls.groupBy(_.length).get(2) |
|
259 |
|
260 |
|
261 |
|
262 // Option type (again) |
|
263 //===================== |
|
264 |
|
265 // remember, in Java if something unusually happens, |
|
266 // you return null; |
|
267 // |
|
268 // in Scala you use Option |
|
269 // - if the value is present, you use Some(value) |
|
270 // - if no value is present, you use None |
|
271 |
|
272 |
|
273 List(7,2,3,4,5,6).find(_ < 4) |
|
274 List(5,6,7,8,9).find(_ < 4) |
|
275 |
|
276 // operations on options |
96 // operations on options |
277 |
97 |
278 val lst = List(None, Some(1), Some(2), None, Some(3)) |
98 val lst = List(None, Some(1), Some(2), None, Some(3)) |
279 |
99 |
280 lst.flatten |
100 lst.flatten |
299 val lst = List(None, Some(1), Some(2), None, Some(3)) |
119 val lst = List(None, Some(1), Some(2), None, Some(3)) |
300 |
120 |
301 for (x <- lst) yield x.getOrElse(0) |
121 for (x <- lst) yield x.getOrElse(0) |
302 |
122 |
303 |
123 |
304 |
|
305 |
|
306 // error handling with Option (no exceptions) |
|
307 // |
|
308 // Try(something).getOrElse(what_to_do_in_an_exception) |
|
309 // |
|
310 import scala.util._ |
|
311 import io.Source |
|
312 |
|
313 |
|
314 Source.fromURL("""http://www.inf.ucl.ac.uk/staff/urbanc/""").mkString |
|
315 |
|
316 Try(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString).getOrElse("") |
|
317 |
|
318 Try(Some(Source.fromURL("""http://www.inf.kcl.ac.uk/staff/urbanc/""").mkString)).getOrElse(None) |
|
319 |
|
320 |
|
321 // a function that turns strings into numbers (similar to .toInt) |
|
322 Integer.parseInt("12u34") |
|
323 |
|
324 |
|
325 def get_me_an_int(s: String) : Option[Int] = |
|
326 Try(Some(Integer.parseInt(s))).getOrElse(None) |
|
327 |
|
328 val lst = List("12345", "foo", "5432", "bar", "x21", "456") |
|
329 for (x <- lst) yield get_me_an_int(x) |
|
330 |
|
331 // summing up all the numbers |
|
332 |
|
333 lst.map(get_me_an_int).flatten.sum |
|
334 lst.map(get_me_an_int).flatten.sum |
|
335 |
|
336 |
|
337 lst.flatMap(get_me_an_int).map(_.toString) |
|
338 |
124 |
339 |
125 |
340 // This may not look any better than working with null in Java, but to |
126 // This may not look any better than working with null in Java, but to |
341 // see the value, you have to put yourself in the shoes of the |
127 // see the value, you have to put yourself in the shoes of the |
342 // consumer of the get_me_an_int function, and imagine you didn't |
128 // consumer of the get_me_an_int function, and imagine you didn't |
352 // even Scala is not immune to problems like this: |
138 // even Scala is not immune to problems like this: |
353 |
139 |
354 List(5,6,7,8,9).indexOf(7) |
140 List(5,6,7,8,9).indexOf(7) |
355 List(5,6,7,8,9).indexOf(10) |
141 List(5,6,7,8,9).indexOf(10) |
356 List(5,6,7,8,9)(-1) |
142 List(5,6,7,8,9)(-1) |
|
143 |
|
144 |
|
145 |
|
146 |
|
147 // Higher-Order Functions |
|
148 //======================== |
|
149 |
|
150 // functions can take functions as arguments |
|
151 |
|
152 def even(x: Int) : Boolean = x % 2 == 0 |
|
153 def odd(x: Int) : Boolean = x % 2 == 1 |
|
154 |
|
155 val lst = (1 to 10).toList |
|
156 |
|
157 lst.filter(x => even(x)) |
|
158 lst.filter(even(_)) |
|
159 lst.filter(even) |
|
160 |
|
161 lst.count(even) |
|
162 |
|
163 |
|
164 lst.find(even) |
|
165 |
|
166 val ps = List((3, 0), (3, 2), (4, 2), (2, 2), (2, 0), (1, 1), (1, 0)) |
|
167 |
|
168 lst.sortWith(_ > _) |
|
169 lst.sortWith(_ < _) |
|
170 |
|
171 def lex(x: (Int, Int), y: (Int, Int)) : Boolean = |
|
172 if (x._1 == y._1) x._2 < y._2 else x._1 < y._1 |
|
173 |
|
174 ps.sortWith(lex) |
|
175 |
|
176 ps.sortBy(_._1) |
|
177 ps.sortBy(_._2) |
|
178 |
|
179 ps.maxBy(_._1) |
|
180 ps.maxBy(_._2) |
|
181 |
|
182 |
|
183 |
|
184 // maps (lower-case) |
|
185 //=================== |
|
186 |
|
187 def double(x: Int): Int = x + x |
|
188 def square(x: Int): Int = x * x |
|
189 |
|
190 |
|
191 val lst = (1 to 10).toList |
|
192 |
|
193 lst.map(x => (double(x), square(x))) |
|
194 |
|
195 lst.map(square) |
|
196 |
|
197 // this is actually how for-comprehensions |
|
198 // defined as in Scala |
|
199 |
|
200 lst.map(n => square(n)) |
|
201 for (n <- lst) yield square(n) |
|
202 |
|
203 // this can be iterated |
|
204 |
|
205 lst.map(square).filter(_ > 4) |
|
206 |
|
207 lst.map(square).filter(_ > 4).map(square) |
|
208 |
|
209 |
|
210 // lets define our own functions |
|
211 // type of functions, for example f: Int => Int |
|
212 |
|
213 lst.tail |
|
214 |
|
215 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = { |
|
216 if (lst == Nil) Nil |
|
217 else f(lst.head) :: my_map_int(lst.tail, f) |
|
218 } |
|
219 |
|
220 my_map_int(lst, square) |
|
221 |
|
222 |
|
223 // same function using pattern matching: a kind |
|
224 // of switch statement on steroids (see more later on) |
|
225 |
|
226 def my_map_int(lst: List[Int], f: Int => Int) : List[Int] = lst match { |
|
227 case Nil => Nil |
|
228 case x::xs => f(x)::my_map_int(xs, f) |
|
229 } |
|
230 |
|
231 |
|
232 // other function types |
|
233 // |
|
234 // f1: (Int, Int) => Int |
|
235 // f2: List[String] => Option[Int] |
|
236 // ... |
|
237 val lst = (1 to 10).toList |
|
238 |
|
239 def sumOf(f: Int => Int, lst: List[Int]): Int = lst match { |
|
240 case Nil => 0 |
|
241 case x::xs => f(x) + sumOf(f, xs) |
|
242 } |
|
243 |
|
244 def sum_squares(lst: List[Int]) = sumOf(square, lst) |
|
245 def sum_cubes(lst: List[Int]) = sumOf(x => x * x * x, lst) |
|
246 |
|
247 sum_squares(lst) |
|
248 sum_cubes(lst) |
|
249 |
|
250 // lets try it factorial |
|
251 def fact(n: Int) : Int = |
|
252 if (n == 0) 1 else n * fact(n - 1) |
|
253 |
|
254 def sum_fact(lst: List[Int]) = sumOf(fact, lst) |
|
255 sum_fact(lst) |
|
256 |
|
257 |
|
258 |
|
259 // if you like verbosity, you can full-specify the literal. |
|
260 // Don't go telling that to people, though |
|
261 (1 to 100).filter((x: Int) => x % 2 == 0).sum |
|
262 |
|
263 // As x is known to be an Int anyway, you can omit that part |
|
264 (1 to 100).filter(x => x % 2 == 0).sum |
|
265 |
|
266 // As each parameter (only x in this case) is passed only once |
|
267 // you can use the wizardy placeholder syntax |
|
268 (1 to 100).filter(_ % 2 == 0).sum |
|
269 |
|
270 // But if you want to re-use your literal, you can also put it in a value |
|
271 // In this case, explicit types are required because there's nothing to infer from |
|
272 val isEven = (x: Int) => x % 2 == 0 |
|
273 (1 to 100).filter(isEven).sum |
|
274 |
|
275 |
|
276 |
|
277 // Option Type again |
|
278 //=================== |
|
279 |
|
280 // a function that turns strings into numbers (similar to .toInt) |
|
281 Integer.parseInt("12u34") |
|
282 |
|
283 |
|
284 def get_me_an_int(s: String) : Option[Int] = |
|
285 Try(Some(Integer.parseInt(s))).getOrElse(None) |
|
286 |
|
287 val lst = List("12345", "foo", "5432", "bar", "x21", "456") |
|
288 for (x <- lst) yield get_me_an_int(x) |
|
289 |
|
290 // summing up all the numbers |
|
291 |
|
292 lst.map(get_me_an_int).flatten.sum |
|
293 lst.map(get_me_an_int).flatten.sum |
|
294 |
|
295 lst.flatMap(get_me_an_int).sum |
|
296 |
|
297 |
|
298 |
|
299 |
|
300 // Map type (upper-case) |
|
301 //======================= |
|
302 |
|
303 // Note the difference between map and Map |
|
304 |
|
305 def factors(n: Int) : List[Int] = |
|
306 ((1 until n).filter { divisor => |
|
307 n % divisor == 0 |
|
308 }).toList |
|
309 |
|
310 |
|
311 var ls = (1 to 10).toList |
|
312 |
|
313 val facs = ls.map(n => (n, factors(n))) |
|
314 |
|
315 facs.find(_._1 == 4) |
|
316 |
|
317 // works for lists of pairs |
|
318 facs.toMap |
|
319 |
|
320 |
|
321 facs.toMap.get(4) |
|
322 facs.toMap.getOrElse(42, Nil) |
|
323 |
|
324 val facsMap = facs.toMap |
|
325 |
|
326 val facsMap0 = facsMap + (0 -> List(1,2,3,4,5)) |
|
327 facsMap0.get(1) |
|
328 |
|
329 val facsMap4 = facsMap + (1 -> List(1,2,3,4,5)) |
|
330 facsMap.get(1) |
|
331 facsMap4.get(1) |
|
332 |
|
333 val ls = List("one", "two", "three", "four", "five") |
|
334 ls.groupBy(_.length) |
|
335 |
|
336 ls.groupBy(_.length).get(2) |
|
337 |
357 |
338 |
358 |
339 |
359 |
340 |
360 // Pattern Matching |
341 // Pattern Matching |
361 //================== |
342 //================== |