【问题标题】:Char or String -> Unicode value in Scala?Scala中的字符或字符串-> Unicode值?
【发布时间】:2021-03-02 14:07:44
【问题描述】:

所以我正在完成“不耐烦的 Scala”中的一些练习,其中之一是:

编写一个for 循环来计算字符串中所有字母的Unicode 代码的乘积。例如,“Hello”中的字符的乘积是 9415087488 L。

下一个问题是做同样的事情,但没有 for 循环 - 它暗示我们应该在 Scaladoc 中检查 StringOps

我检查了 Scaladoc 中的 RichCharStringOps 部分,也许我误读或看错了地方,但我找不到任何可以让我匹配他们的输出的东西。到目前为止,我已经尝试过:

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 方式执行此操作?

谢谢!

【问题讨论】:

  • 还有另一种方法,如果您分两步完成。提示:这两个方法中的最后一个只有一个隐式参数。

标签: scala unicode


【解决方案1】:

当您执行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

【讨论】:

  • 也感谢我。奇怪的是,在我刚刚下载的pdf-Version中,给出了错误的值(825152896)。
  • 很奇怪,但是对于 "for (fi
  • @Dubysa i 变量的类型是什么?您的 i 需要是 Long 才能获得正确的结果,否则 Scala 会将表达式推断为 Int(带有 Char 的 Int 倍数将成为 Int),这将导致溢出。
  • 好吧,我的 REPL 没有发现问题(我一直都知道我的笔记本电脑很智能 :D)我确实将其发布为答案。
  • 也可以写成(x :\ 1L)(_ * _)
【解决方案2】:

如果您将 String 的每个 RichChar 转换为 .toLong 它也可以。例如,这个:

str.map (_.toLong).product - 工作正常,没有 foldLeft 或循环

这是循环变体:

def product(str: String): Long = {
    var prod: Long = 1
    for (ch <- str) prod *= ch
    prod
}

【讨论】:

    【解决方案3】:

    StringOps 中有一个特殊的“product”方法,可以将集合的元素相乘。但它使用 Char 类型,因为字符串由 char 元素组成。我们在尝试计算“Hello”.product 时出现溢出。因此,我通过 "Hello".map(_.toLong) 将字符串转换为 Long Unicode 值的向量,并通过以下代码计算其元素的乘积:

    scala> "Hello".map(_.toLong).product
    res79: Long = 9415087488
    

    【讨论】:

    • 谢谢!我也怀疑溢出了。但不确定如何要求它映射到 Long。
    • Rihad 答案中的 for 循环和此答案中的地图是符号变体。我相信编译器会将 for 循环转换为映射。这是您使用的口味问题。
    【解决方案4】:

    这是另一种方式:

    scala> (for (c <- "Hello") yield c.toLong).product
    res36: Long = 9415087488
    

    【讨论】:

      【解决方案5】:

      我发现的最直接的方法是:

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

      【讨论】:

        【解决方案6】:

        我认为转换为中间映射效率低下,因为在这种情况下,集合被迭代两次:一次是创建 long 的映射,第二次是乘以所有元素。也不需要龙氏不必要的临时收集。我投票给

        "Hello".foldLeft(1L)(_ * _)
        

        【讨论】:

          【解决方案7】:

          不使用for循环所需的练习,所以我已经递归了:

          def unicode_rec(s: String): Int = 
            if(s == "") 1 
            else s.head.toInt * unicode_rec(s.tail)
          

          【讨论】:

          • 递归函数也是我对解决方案的第一个直觉。您实际上可以省略s.head.toInt.toInt 部分,因为.head返回一个Char。此外,要从本书的新版本 (9415087488L) 中获得非溢出结果,函数的返回类型应为 LongBigInt :-)
          【解决方案8】:

          另一种变体:

          "Hello".aggregate(1L)({(prod,ch) => prod * ch.toLong}, {(p1,p2)=>p1*p2})
          

          【讨论】:

            【解决方案9】:

            所以我们在这里聚在一起:)

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

            【讨论】:

              【解决方案10】:

              在同一本书上也取得了进展。 可能看起来有点像 java 风格,但它确实发挥了作用:

              scala> "Hello".map( x => x.toLong).reduce( (a, b) => a * b)
              val res45: Long = 9415087488
              

              【讨论】:

              • 1st - 这个解决方案是一年前发布的。第二 - 825152896 是错误的结果。重新阅读 8 年前的问题和所有其他答案。
              • 第一个 - 不同的解决方案。第二:825152896 是本书本身的产品:)。改为使用 long / unicode。
              • Re-1st:是的。请参阅 R Sun 发布的“9th way”。
              猜你喜欢
              • 1970-01-01
              • 2011-08-09
              • 2019-04-09
              • 1970-01-01
              • 1970-01-01
              • 2019-05-12
              • 2020-09-09
              相关资源
              最近更新 更多