我尝试使用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 comprehension返回scala.collection.immutable.IndexedSeq[AnyVal]
,而该函数必须返回Array[Int]
,因此它会抛出type mismatch error
。
有没有办法让for comprehension返回一个Array [Int]或将IndexedSeq[AnyVal]
转换为Array[Int]
?
答案 0 :(得分: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语句的问题在于没有默认值,这就是为什么你得到一个Any的IndexedSeq而不是Int。
答案 1 :(得分:2)
这里有两个问题,第一个来自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
。
答案 2 :(得分:2)
您可以通过调用IndexedSeq
将Array
强制转换为toArray
,这样第一位非常简单。对于第二部分,因为您可以在所有if... else...
个案例中删除可能的逻辑分支,所以yield
可能会返回Int
和Unit
类型,最近的共同祖先是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
}