Reputation: 768
So this might not be the best way to tackle it but my initial thought was a for expression. Say I have a List like
List(List('a','b','c'),List('d','e','f'),List('h','i','j'))
I would like to find the row and column for a character, say 'e'
.
def findChar(letter: Char, list: List[List[Char]]): (Int, Int) =
for {
r <- (0 until list.length)
c <- (0 until list(r).length)
if list(r)(c) == letter
} yield (r, c)
If there is a more elegant way I'm all ears but I would also like to understand what's wrong with this. Specifically the error the compiler gives me here is
type mismatch; found : scala.collection.immutable.IndexedSeq[(Int, Int)] required: (Int, Int)
on the line assigning to r
. It seems to be complaining that my iterator doesn't match the return type but I don't quite understand why this is or what to do about it ...
Upvotes: 0
Views: 241
Reputation: 39577
For your other ear, the question duplicates
How to capture inner matched value in indexWhere vector expression?
scala> List(List('a','b','c'),List('d','e','f'),List('h','i','j'))
res0: List[List[Char]] = List(List(a, b, c), List(d, e, f), List(h, i, j))
scala> .map(_ indexOf 'e').zipWithIndex.find(_._1 > -1)
res1: Option[(Int, Int)] = Some((1,1))
Upvotes: 2
Reputation: 5028
In the signature of findChar
you are telling the compiler that it returns (Int, Int)
. However, the result of your for
expression (as inferred by Scala) is IndexedSeq[(Int, Int)]
as the error message indicates. The reason is that (r, c)
after yield
is produced for every "iteration" in the for
expression (i.e., you are generating a sequence of results, not just a single result).
EDIT: As for findChar
, you could do:
def findChar(letter: Char, list: List[List[Char]]) = {
val r = list.indexWhere(_ contains letter)
val c = list(r).indexOf(letter)
(r, c)
}
It is not the most efficient solution, but relatively short.
EDIT: Or reuse your original idea:
def findAll(letter: Char, list: List[List[Char]]) =
for {
r <- 0 until list.length
c <- 0 until list(r).length
if list(r)(c) == letter
} yield (r, c)
def findChar(c: Char, xs: List[List[Char]]) = findAll(c, xs).head
In both cases, be aware that an exception occurs if the searched letter is not contained in the input list.
EDIT: Or you write a recursive function yourself, like:
def findPos[A](c: A, list: List[List[A]]) = {
def aux(i: Int, xss: List[List[A]]) : Option[(Int, Int)] = xss match {
case Nil => None
case xs :: xss =>
val j = xs indexOf c
if (j < 0) aux(i + 1, xss)
else Some((i, j))
}
aux(0, list)
}
where aux
is a (locally defined) auxiliary function that does the actual recursion (and remembers in which sublist we are, the index i
). In this implementation a result of None
indicates that the searched element was not there, whereas a successful result might return something like Some((1, 1))
.
Upvotes: 2