Scala convert IndexedSeq [AnyVal] to Array [Int]
I am trying to solve Codility GenomicRangeQuery using Scala and for this purpose I wrote the following function:
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
}
}
I haven't tested much, but it seems to have solved the problem.
My problem is that, to understand, returns scala.collection.immutable.IndexedSeq[AnyVal]
, and the function has to return Array[Int]
and therefore throw type mismatch error
.
Is there a way to make it return Array [Int], or convert IndexedSeq[AnyVal]
to Array[Int]
?
source to share
Sheunis' answer above mostly covers it.
You can force IndexedSeq
to Array
a call toArray
to the first bit it was pretty simple. For the second part, since there is a possible logical branch where you can go through all of your cases if... else...
, it is possible that yours yield
should return types Int
and Unit
whose closest common ancestor is AnyVal
.
Note that if you replace yours if... else...
with pattern matching, you will explicitly get a compiler warning because you won't catch all the possible ones 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
}
source to share
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
}
The problem with the if statement is that there is no default value, so you get IndexedSeq from Any and not Int.
source to share
There are two problems here, the first one p.indices
, which returns scala.collection.immutable.Range
instead Array
. Doing it p.indices.toArray
(or adding .toArray
at the end as @sheunis suggested) fixes the problem.
Another problem comes from your if statement, which is incomplete, if all conditions are false, your method returns (): Unit
(which was added by the compiler). Adding a default case, for example else -1
as the last statement, should solve this second problem.
Edit . If the default case can never be added, you can make an exception like this:
else {
val err = "the input String can only contain the characters ACGT"
throw new IllegalArgumentException(err)
}
This informs both the next programmer and the compiler about what's going on in your code. Note that expressions throw
are of type Nothing
, so when calculating the smallest upper bound, (Int, Int, Int, Nothing)
output correctly Int
, as opposed to (Int, Int, Int, Unit)
which is lubed before AnyVal
.
source to share