【问题标题】:Scala convert IndexedSeq[AnyVal] to Array[Int]Scala 将 IndexedSeq[AnyVal] 转换为 Array[Int]
【发布时间】:2017-05-19 08:12:38
【问题描述】:

我正在尝试使用 Scala 解决 Codility 的 GenomicRangeQuery 问题,为此我编写了以下函数:

def solution(s: String, p: Array[Int], q: Array[Int]): Array[Int] = {
  for (i <- p.indices) yield {
    val gen = s.substring(p(i), q(i) + 1)
    if (gen.contains('A')) 1
    else if (gen.contains('C')) 2
    else if (gen.contains('G')) 3
    else if (gen.contains('T')) 4
  }
}

我没有做很多测试,但似乎可以解决问题。

我的问题是 for 理解返回 scala.collection.immutable.IndexedSeq[AnyVal],而函数必须返回 Array[Int],因此它抛出了 type mismatch error

有没有办法让 for 理解返回 Array[Int] 或将 IndexedSeq[AnyVal] 转换为 Array[Int]

【问题讨论】:

    标签: arrays scala


    【解决方案1】:

    sheunis 上面的回答主要涵盖了它。

    您可以通过调用toArrayIndexedSeq 强制转换为Array,因此第一部分非常简单。对于第二部分,由于可能存在一个逻辑分支,您可以在其中遍历所有 if... else... 案例,因此您的 yield 可能会返回 IntUnit 类型,它们最接近的共同祖先是 AnyVal .

    请注意,如果您将 if... else... 替换为模式匹配,则会显式收到编译器警告,因为您没有捕获所有可能的 case

    gen match { case _ if gen.contains("A") => 1 case _ if gen.contains("C") => 2 ... // Throws warning unless you include a `case _ =>` with no `if` clause }

    【讨论】:

    • 谢谢,这行得通,我不需要添加默认情况。
    • "你会明确地得到一个编译器警告,因为你没有捕捉到所有可能的情况" 不,你不会;这只发生在匹配 sealed 类型的值并且在匹配表达式中使用任何守卫即使在这种情况下也会禁用警告时发生。
    【解决方案2】:
    def solution(s: String, p: Array[Int], q: Array[Int]): Array[Int] = {
      (for (i <- p.indices) yield {
        val gen = s.substring(p(i), q(i) + 1)
        if (gen.contains('A')) 1
        else if (gen.contains('C')) 2
        else if (gen.contains('G')) 3
        else 4
      }).toArray
    }
    

    if 语句的问题是没有默认值,这就是为什么你得到的 IndexedSeq 是 Any 而不是 Int。

    【讨论】:

    • 调用toArray会将返回类型变成Array[AnyVal],这仍然不匹配Array[Int]
    • @Micho 添加一个 else 来处理默认情况将返回 Array[Int]。 OP 的原始代码不会,因为他没有涵盖所有潜在的情况。
    【解决方案3】:

    这里有两个问题,第一个来自p.indices,它返回scala.collection.immutable.Range 而不是Array。执行p.indices.toArray(或像@sheunis 建议的那样在最后添加.toArray)解决了这个问题。

    另一个问题来自您的 if 语句不完整,如果所有条件都为假,您的方法将返回 (): Unit (由编译器添加)。添加默认情况,例如 else -1 作为最后一个语句应该可以解决第二个问题。

    编辑:如果默认大小写永远无法追加,您可以如下抛出异常:

    else {
      val err = "the input String can only contain the characters ACGT"
      throw new IllegalArgumentException(err)
    }
    

    这会通知下一个程序员和编译器你的代码中发生了什么。请注意throw 表达式的类型为Nothing,因此当计算(Int, Int, Int, Nothing) 的最小上限时,正确地产生Int,不像(Int, Int, Int, Unit),它被润滑到AnyVal

    【讨论】:

    • 输入String只能包含ACGT字符的问题的前提条件。正如@sheunis 回答所发生的那样,调用p.indices.toArray 或在for 理解将返回类型转换为Array[AnyVal] 之后调用它,这仍然与Array[Int] 不匹配。
    • 我的回答的第二部分解释了为什么你会得到 Array[AnyVal] 以及如何修复它,请参阅编辑以获取默认值的替代方案。
    猜你喜欢
    • 2016-06-10
    • 2020-09-10
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 1970-01-01
    相关资源
    最近更新 更多