请选择 进入手机版 | 继续访问电脑版
楼主: Scalachen
3652 24

Learning Scala [推广有奖]

Lisrelchen 发表于 2016-4-4 00:39:23 |显示全部楼层 |坛友微信交流群
  1. 3.2) Given a double amount, write an expression to return "greater" if it is more than zero, "same" if it equals zero, and "less" if it is less than zero. Can you write this with if..else blocks? How about with match expressions?

  2. Answer

  3. First, here’s the if..else block (specifically an if..else-if..else block).

  4. scala> val amount = 2.143
  5. amount: Double = 2.143

  6. scala> if (amount > 0) "greater" else if (amount < 0) "lesser" else "same"
  7. res0: String = greater
  8. Second, the match expression that achieves the same purpose.

  9. scala> amount match {
  10.      |   case x if x > 0 => "greater"
  11.      |   case x if x < 0 => "lesser"
  12.      |   case x => "same"
  13.      | }
  14. res1: String = greater
  15. Which solution do you prefer? I find the match expression a bit more readable but the if..else block is certainly more compact.
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:40:11 |显示全部楼层 |坛友微信交流群
  1. 3.3) Write an expression to convert one of the input values "cyan", "magenta", "yellow" to their 6-char hexadecimal equivalents in string form. What can you do to handle error conditions?

  2. Answer

  3. Returning an appropriate hexadecimal version of one of the three possible color names is easy enough. A good error handling solution should check if an unexpected color name was given and log the error, while still returning a useful color.

  4. scala> val color = "magenta"
  5. color: String = magenta

  6. scala> color match {
  7.      |   case "cyan" => "00ffff"
  8.      |   case "magenta" => "00ff00"
  9.      |   case "yellow" => "ffff00"
  10.      |   case x => {
  11.      |     println(s"Didn't expect $x !")
  12.      |     "333333"
  13.      |   }
  14.      | }
  15. res0: String = 00ff00
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 00:40:42 |显示全部楼层 |坛友微信交流群
  1. 3.4) Print the numbers 1 to 100, with each line containing a group of 5 numbers. For example:

  2. 1, 2, 3, 4, 5,
  3. 6, 7, 8, 9, 10
  4. ....
  5. Answer

  6. Two for-loops, one for the rows and one for the columns, can handle this task.

  7. scala> for (i <- 1 to 100 by 5) {
  8.      |   for (j <- i to (i + 4)) { print(s"$j, ") }
  9.      |   println("")
  10.      | }
  11. 1, 2, 3, 4, 5,
  12. 6, 7, 8, 9, 10,
  13. 11, 12, 13, 14, 15,
  14. ...
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:02:00 |显示全部楼层 |坛友微信交流群
  1. 3.5) There is a popular coding interview question I’ll call "typesafe", in which the numbers 1 - 100 must be printed one per line. The catch is that multiples of 3 must replace the number with the word "type", while multiples of 5 must replace the number with the word "safe". Of course, multiples of 15 must print "typesafe".

  2. Answer

  3. There’s a number of ways to solve this. Here’s a solution that isn’t very compact but plainly checks for the greatest factor (15) before checking for 5 and 3.

  4. scala> for (i <- 1 to 100) {
  5.      |   i match {
  6.      |     case x if x % 15 == 0 => println("typesafe")
  7.      |     case x if x % 5 == 0 => println("safe")
  8.      |     case x if x % 3 == 0 => println("type")
  9.      |     case x => println(x)
  10.      |   }
  11.      | }
  12. 1
  13. 2
  14. type
  15. 4
  16. safe
  17. ...
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:02:34 |显示全部楼层 |坛友微信交流群
  1. 3.6) Can you rewrite the answer to question 5 to fit on one line? It probably won’t be easier to read, but reducing code to its shortest form is an art, and a good exercise to learn the language.

  2. Answer

  3. Note: in the first edition of the book the text says "answer to question 6", which is accidentally recursive. It should have said "answer to question 5".

  4. To make this fit on a single line, I switched to a mutable string which could hold "type" and "safe". It can also be checked for emptiness and thus print the current integer value.

  5. scala> for (i <- 1 to 100) { var s = ""; if (i%3==0) s="type"; if (i%5==0) s+="safe"; if(s.isEmpty) s += i; println(s) }
  6. 1
  7. 2
  8. type
  9. 4
  10. safe
  11. type
  12. 7
  13. 8
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:03:19 |显示全部楼层 |坛友微信交流群
  1. 4.1) Write a function that computes the area of a circle given its radius.

  2. Answer

  3. A circle’s area is equal to the square of its radius times Pi. A quick and dirty solution of multiplying the radius twice with a reasonable hard coded version of Pi will get us close to the solution.

  4. scala> def circleArea(r: Double) = r * r * 3.14159
  5. circleArea: (r: Double)Double

  6. scala> circleArea(8)
  7. res0: Double = 201.06176
  8. We can make use of scala.math to handle the square of the radius and a more approximate version of Pi, if more accuracy is desired.

  9. scala> def circleArea2(r: Double) = math.pow(r,2) * math.Pi
  10. circleArea2: (r: Double)Double

  11. scala> circleArea2(8)
  12. res1: Double = 201.06192982974676
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:04:31 |显示全部楼层 |坛友微信交流群
  1. 4.2) Provide an alternate form of the function in #1 that takes the radius as a String. What happens if your function is invoked with an empty String ?

  2. Answer

  3. Providing the radius as a double number encoded as a string makes the function a little more complex. Not only will it be necessary to try to convert the string, but we’ll have to figure out an acceptable result when the string is empty.

  4. As this function takes up more than a single line, I’ll add an explicit return type for clarity and also wrap the function body in curly braces. I’ll also go ahead with the number zero as the return value when the input radius is empty.

  5. A more advanced version of this function would also handle completely invalid radius values in the input string, such as "Hello" or "123abc". However, this function won’t include that case, as it requires exception handling which we haven’t yet covered.

  6. scala> def circleArea3(r: String): Double = {
  7.      |   r.isEmpty match {
  8.      |     case true => 0
  9.      |     case false => math.pow(r.toDouble,2) * math.Pi
  10.      |   }
  11.      | }
  12. circleArea3: (r: String)Double

  13. scala> circleArea3("8")
  14. res2: Double = 201.06192982974676

  15. scala> circleArea3("")
  16. res3: Double = 0.0
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:05:07 |显示全部楼层 |坛友微信交流群
  1. 4.3) Write a recursive function that prints the values from 5 to 50 by fives, without using for or while loops. Can you make it tail-recursive?

  2. Answer

  3. Recursive functions that have no return value are rather easy to write, as the result of invoking the function is ignored. The "@annotation.tailrec" will work easily as there is no return value which may be saved locally; we can simply exit immediately after the invocation.

  4. Here’s my version of this recursive function. Can you find a shorter, simpler way to write this?

  5. scala> @annotation.tailrec
  6.      | def fives(cur: Int, max: Int): Unit = {
  7.      |   if (cur <= max) {
  8.      |     println(cur)
  9.      |     fives(cur + 5, max)
  10.      |   }
  11.      | }
  12. fives: (cur: Int, max: Int)Unit

  13. scala> fives(0, 20)
  14. 0
  15. 5
  16. 10
  17. 15
  18. 20
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:06:40 |显示全部楼层 |坛友微信交流群
  1. 4) Write a function that takes a milliseconds value and returns a string describing the value in days, hours, minutes and seconds. What’s the optimal type for the input value?

  2. Answer

  3. The common format for using milliseconds to describe a time is using the value zero to indicate 12:00 am GMT on January 1st, 1970. Also known as "epoch time", this format is supported by the JVM library classes java.util.Date and java.util.Calendar, among others.

  4. However, we can write this function without making use of the JVM classes. Here’s a version that expects the epoch time in milliseconds specified as a long value. Using a long value (64 bits) ensures that the code will work for millenia.

  5. The first step is to reduce the milliseconds down to a more reasonable seconds value. The days is computed by dividing the seconds by the seconds in a day, while the remaining values are computed by modules of the nearest larger time unit.

  6. scala> def descTime(epochMs: Long) = {
  7.      |   val secs = epochMs / 1000
  8.      |
  9.      |   val days = secs / 86400
  10.      |   val hours = (secs % 86400) / 3600
  11.      |   val minutes = (secs % 3600) / 60
  12.      |   val seconds = secs % 60
  13.      |   s"$days days, $hours hours, $minutes minutes, $seconds seconds"
  14.      | }
  15. descTime: (epochMs: Long)String

  16. scala> descTime(123456789000L)
  17. res20: String = 1428 days, 21 hours, 33 minutes, 9 seconds
复制代码

使用道具

Lisrelchen 发表于 2016-4-4 01:08:10 |显示全部楼层 |坛友微信交流群
  1. 5) Write a function that calculates the first value raised to the exponent of the second value. Try writing this first using math.pow, then with your own calculation. Did you implement it with variables? Is there a solution available that only uses immutable data? Did you choose a numeric type that is large enough for your uses?

  2. Answer

  3. Here’s the easy way, using the math.pow library function.

  4. scala> def pow(x: Double, y: Double): Double = math.pow(x,y)
  5. pow: (x: Double, y: Double)Double

  6. scala> pow(2, 5)
  7. res0: Double = 32.0
  8. Using a custom calculation, here’s a version that stores the intermediate results in a variable. It’s not especially robust, since it doesn’t do validation on the exponent (eg, checking if a negative number was given).

  9. scala> def pow(x: Double, y: Int): Double = {
  10.      |   var p = 1.0; for (i <- 1 to y) p *= x; p
  11.      | }
  12. pow: (x: Double, y: Int)Double

  13. scala> pow(2, 5)
  14. res1: Double = 32.0
复制代码

使用道具

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
加JingGuanBbs
拉您进交流群

京ICP备16021002-2号 京B2-20170662号 京公网安备 11010802022788号 论坛法律顾问:王进律师 知识产权保护声明   免责及隐私声明

GMT+8, 2024-3-29 02:09