Reputation: 3
I'm currently learning scala and am confused about an error I'm getting. I'm trying to play around with the different containers and currently I have a list of maps with each map sharing the same keys. I'm attempting to use a for loop to iterate through the list and put the values corresponding to the key "startlocation" into an array of type Node (class I made), but I can't seem to get the syntax right. It's telling me my key is an incorrect argument while trying to get the value at that key from the current map I'm at within the list.
What is wrong with this code and what should I do to fix it?
class Node{
var visited = false;
var mDistance = 10000;
var prevLoc = " ";
}
object test{
def main(args: Array[String]){
var i = 0;
var l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10),
Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));
var b = new Array[Node](l.size);
var index = 0;
for(i <- l){
b(index).prevLoc = i("startlocation"); // This is the line where the error occurs
index++;
}
}
}
Specific error: type mismatch; found : Any required: String
This error is highlighting the "startlocation" in the line I commented above.
Upvotes: 0
Views: 938
Reputation: 16308
First there is big trouble in definition of your map. Since you use Int
and String
as value type, resulting type is inferred as most possible concrete common supertype of those values, which is Any
, since String
and Int
are pretty different.
Correct approach? It look like your maps are intented to have predefined set of keys, which in scala much better implemented via class
es or even better case class
es so near the Node
class you can define
case class Route(startLocation: String, endLocation: String, distance: Int)
and later
val l = List(
Route( startLocation = "Kruthika's abode", endLocation = "Mark's crib", distance = 10),
Route( startLocation = "Mark's Crib", endLocation = "Kirk's Farm", distance = 9))
or even
val l = List(
Route( "Kruthika's abode", "Mark's crib", 10),
Route( "Mark's Crib", "Kirk's Farm", 9))
and finally
b(index).prevLoc = i.startLocation // This is the line where the error occurs
There is no such thing as postfix ++
operator in scala, so your index++
should be at least index += 1
var
iablesVery often you may avoid var
definition.
For instance var i = 0;
is excessive since it's not even used in your code
because in the for(i <- l)
new i
definition is created which is valid only inside the loop
Also you can avoid definition of var index
, you can iterate over collection with index as
for((i, index) <- l.zipWithIndex)
likewise you can very often avoid var
iables in your class
es, making classes immutable. Instead of mutating you can create new instance (maybe .copy()
ing exisitng) every time when you need.
This is crucial for you code, since b(index).prevLoc
will definitely throw NullPointerException
, because no instance of Node
is created inside you array.
Imagine you defined
case class Node(visited: Boolean = false, mDistance: Int = 10000, prevLoc: String = " ")
And use is as
Node(prevLoc = i.startLocation)
for
(list ≺ sequence ≺ monad) comprehensionsFinally your b
could be now translated to val
of immutable List
since for
is the expression that would create new collection from existing via yield
. With such declaration you don't even need to know current index, so you can drop suggested .zipWithIndex
part
;
And most finally - you can avoid ;
at end of the line almost any time
Concluding, whole you code could be translated to
case class Node(visited: Boolean = false, mDistance: Int = 10000, prevLoc: String = " ")
case class Route(startLocation: String, endLocation: String, distance: Int)
object test{
def main(args: Array[String]){
val l = List(
Route( "Kruthika's abode", "Mark's crib", 10),
Route( "Mark's Crib", "Kirk's Farm", 9))
val b = for(i <- l) yield Node(prevLoc = i.startLocation)
}
}
you can add println(b)
to end of main
method to view how List
and case classes
could be printed
Upvotes: 5
Reputation: 3887
You could try this way,
val l = List(Map("startlocation" -> "Kruthika's abode", "endlocation" -> "Mark's crib", "distance" -> 10),
Map("startlocation" -> "Mark's Crib", "endlocation" -> "Kirk's Farm", "distance" -> 9));
case class Node(visited:Boolean = false, mDistance:Int = 10000, prevLoc:String)
l.map(x=>Node(prevLoc = x("startlocation").asInstanceOf[String]))
Upvotes: 1
Reputation: 3182
It's because you have mixed String and Int types in your maps. The 'prevLoc' seems to be a String, but your map contains Any (scala compiler infer this type, because you have not specified any).
I would suggest you to make your maps explicit like Map[String, String]
. In this case your program will not compile (you have some ints as map values, sou you can do something like "distance" -> 10.toString
).
P.S. try to avoid using var
: it is possible to write Scala code without it, using immutable variables (val
s) and functions like map
, filter
, flatMap
in functional way.
Upvotes: 2