Pooya
Pooya

Reputation: 4481

Why I've got type mismatch exception?

I got a weird exception in this snippet

 val splitted = "This is a text that to test something".split("\\,|\\ ")
 val map = mutable.Map[Int, List[String]]()
 (0 to splitted.length).foreach {
     case i =>map(i) = map.getOrElse(i,List[String]("")) ++ splitted(i)
 }

but I have got this exception:

type mismatch;
 found   : List[Any]
 required: List[String]
      case i =>map(i) = map.getOrElse(i,List("")) ++ splitted(i)
                                              ^                                                  ^

Upvotes: 0

Views: 1484

Answers (4)

Giovanni Botta
Giovanni Botta

Reputation: 9816

Not sure what you're trying to do with that code but here's a working version:

(0 to splitted.length-1).foreach {
  case i =>map(i) = (map.getOrElse(i,List[String]("")) :+ splitted(i))
}

which will create:

println(map)
Map(2 -> List(, a), 5 -> List(, to), 4 -> List(, that), 7 -> List(, something), 1 -> List(, is), 3 -> List(, text), 6 -> List(, test), 0 -> List(, This))

EDIT: Maybe what you need is the following:

splitted.zipWithIndex.map{case (s,i)=>(i,s)}.toMap

which results in:

Map(0 -> This, 5 -> to, 1 -> is, 6 -> test, 2 -> a, 7 -> something, 3 -> text, 4 -> that)

or more efficiently:

((0 to splitted.length-1) zip splitted).toMap

Upvotes: 1

som-snytt
som-snytt

Reputation: 39577

You are yet another victim of the inference of Any.

scala> map.getOrElse(7,List[String](""))
res3: List[String] = List("")

scala> res3 ++ "abc"
res4: List[Any] = List("", a, b, c)

Here's the same thing with -Xlint:

scala> (0 to splitted.length).foreach {
     case i =>map(i) = map.getOrElse(i,List[String]("")) ++ splitted(i)
 }
<console>:12: error: type mismatch;
 found   : List[Any]
 required: List[String]
                   case i =>map(i) = map.getOrElse(i,List[String]("")) ++ splitted(i)
                                                                       ^

scala> val res3 = { map.getOrElse(7,List[String]("")) }
<console>:6: warning: Unused import
import collection.mutable
                  ^
res3: List[String] = List("")

scala> res3 ++ "abc"
<console>:11: warning: a type was inferred to be `Any`; this may indicate a programming error.
              res3 ++ "abc"
                      ^
res1: List[Any] = List("", a, b, c)

Unfortunately, the -Xlint warning is smothered by the error.

And, under -Xlint -Xfatal-warnings, the warning doesn't get a chance to error out:

scala> (0 to splitted.length).foreach {
     case i =>map(i) = map.getOrElse(i,List[String]("")) ++ splitted(i)
 }
<console>:11: error: type mismatch;
 found   : List[Any]
 required: List[String]
                   case i =>map(i) = map.getOrElse(i,List[String]("")) ++ splitted(i)
                                                                       ^

If the warning is not inside the closure, then you get the helpful message under -Xlint -Xfatal-warnings:

val ss: List[String] = (null: mutable.Map[Int,List[String]]).getOrElse(0,List.empty[String]) ++ "abc"

Upvotes: 2

Kigyo
Kigyo

Reputation: 5768

splitted(i) is a String and ++ (which expects a collection) treats String like Array[Char], which then results in the common supertype List[Any].

Example:

val list = List("a", "b") ++ "hello"
println(list) //prints List(a, b, h, e, l, l, o) and is of type List[Any]

If it doesn't matter where it's inserted then i would do it like this:

case i => map(i) = splitted(i) :: map.getOrElse(i,List[String](""))

If it should be appended:

case i => map(i) = map.getOrElse(i,List[String]("")) :+ splitted(i)

Upvotes: 2

Brian
Brian

Reputation: 20285

This works.

 val splitted = "This is a text that to test something".split("\\,|\\ ")
 val map = scala.collection.mutable.Map[Int, List[String]]()
 (0 until splitted.length).foreach {
     case i =>map(i) = map.getOrElse(i,List[String]("")) :+ splitted(i)
 }

Which outputs:

scala.collection.mutable.Map[Int,List[String]] = Map(2 -> List("", a), 5 -> List("", to), 4 -> List("", that), 7 -> List("", something), 1 -> List("", is), 3 -> List("", text), 6 -> List("", test), 0 -> List("", This))

Also, note the difference between to and until. Using to in will give and ArrayOutOfBoundsException.

scala> val l = List(1,2,3)
l: List[Int] = List(1, 2, 3)
scala> 0 to l.length
res51: scala.collection.immutable.Range.Inclusive = Range(0, 1, 2, 3)
scala> 0 until l.length
res52: scala.collection.immutable.Range = Range(0, 1, 2)

Upvotes: 0

Related Questions