所以我正在完成"Scala for the Impatient"中的一些练习,其中一个是:
编写一个 for
循环,用于计算字符串中所有字母的 Unicode 代码的乘积。比如《你好》中人物的乘积是9415087488 L。
下一个问题是做同样的事情,但没有for
循环 - 它暗示我们应该在 Scaladoc 中检查StringOps
。
我检查了 Scaladoc 中的RichChar
和StringOps
部分,也许我读错了或看错了地方,但我找不到任何让我匹配他们的输出的东西。到目前为止,我已经尝试过:
scala> x.foldLeft(1)(_ * _.toInt)
res0: Int = 825152896
scala> x.foldLeft(1)(_ * _.getNumericValue)
res5: Int = 2518992
scala> x.foldLeft(1)(_ * _.intValue())
res6: Int = 825152896
scala> var x = 1
x: Int = 1
scala> for (c <- "Hello") x *= c.toInt
scala> x
res12: Int = 825152896
这与他们的输出不匹配。
我如何以for
和非for
的方式做到这一点?
谢谢!
当你做x.foldLeft(1)(_ * _.toInt)
时,结果类型将是推断到一个Int
,但9415087488太大,Int
无法存储它。
所以你需要告诉Scala使用Long
来存储它。
scala> val x = "Hello"
x: java.lang.String = Hello
scala> x.foldLeft(1L)(_ * _.toInt)
res1: Long = 9415087488
scala> var x: Long = 1
x: Long = 1
scala> for (c <- "Hello") x *= c.toInt
scala> x
res7: Long = 9415087488
如果你转换字符串的每个 RichChar .toLong,它也可以工作。例如,这个:
str.map (_.toLong).product
- 工作很好,没有折叠左或循环
这是循环变体:
def product(str: String): Long = {
var prod: Long = 1
for (ch <- str) prod *= ch
prod
}
StringOps 中有一个特殊的"product"方法,它可以将集合的元素相乘。但它使用 Char 类型,因为字符串由 char 元素组成。我们在尝试计算"Hello".product时出现溢出。因此,我通过"Hello".map(_.toLong)将字符串转换为Long Unicode值的向量,并通过以下代码计算其元素的乘积:
scala> "Hello".map(_.toLong).product
res79: Long = 9415087488
这是另一种方式:
scala> (for (c <- "Hello") yield c.toLong).product
res36: Long = 9415087488
我发现最直接的方法是:
"Hello".foldLeft(1L)((x:Long, y:Char) => x*y)
该方法采用两个参数:Long 和委托函数,该函数采用 Long 和 Char 并返回 Long。 你可以像这样直接传入一个匿名函数,也可以在其他地方定义函数并传入,如下所示:
def multiply(x:Long, y:Char) = {
x*y
}
"Hello".foldLeft(1L)(multiply)
我认为转换为中间映射效率低下,因为在这种情况下,集合迭代了两次:一次用于创建长整型映射,第二次用于乘以所有元素。也不需要不必要的临时收集龙氏。我投票给
"Hello".foldLeft(1L)(_ * _)
for 循环所需的练习,所以我已经递归了:
def unicode_rec(s: String): Int =
if(s == "") 1
else s.head.toInt * unicode_rec(s.tail)
另一个变体:
"Hello".aggregate(1L)({(prod,ch) => prod * ch.toLong}, {(p1,p2)=>p1*p2})
所以在这里我们聚集在一起:)
// one way
val longs = for (c <- str) yield c.toLong
println(longs.product)
// 2nd way
println(str.foldLeft(1L)(_ * _.toInt))
// 3rd way
var x = 1L
for (c <- str) yield x *= c.toInt
println(x)
// 4th way
var product = 1L
for (c <- str) {
product *= c.toInt
}
println(product)
// 5th way
println(str.map(_.toLong).product)
// 6th way
println(str.foldLeft(1L)(_ * _))
// 7th way
println(str.map(_.toLong).reduceLeft(_ * _)) // my IDE warns `Replace reduce with product`
// 8th way
println(str.map(_.toLong).scanLeft(1L)(_ * _).last)
// 9th way
println(str.map(_.toLong).reduce((x, y) => (x * y))) // my IDE warns `Replace reduce with product`
// using recursion
def exercise9(str: String): Long = {
var product = str.head.toLong
if (str.tail.length > 0) {
product *= exercise9(str.tail)
}
product
}
本书中前进。可能看起来有点爪哇味,但它确实完成了它的工作:
scala> "Hello".map( x => x.toLong).reduce( (a, b) => a * b)val res45:多头 = 9415087488