0

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.

1
  • Note: a for comprehension creates its own local variables, so for (i <- l) creates i of type Map[String,Any]. You're var i = 0 creates a variable of type Int that is never used. Commented Nov 27, 2015 at 5:44

3 Answers 3

5

Errors

Heterogenous maps

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 classes or even better case classes 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

Style guide

variables

Very 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)

Immutability

likewise you can very often avoid variables in your classes, 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) comprehensions

Finally 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

Sign up to request clarification or add additional context in comments.

2 Comments

Well done, but zipWithIndex has created an index you don't use or need.
@jwvh Nice catch. Fixed
2

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 (vals) and functions like map, filter, flatMap in functional way.

2 Comments

I wonder if there is a way to do it how I have my maps because I'm currently trying to complete a coding challenge where the input is given to me in the format my maps are in. If this is illegal/inconsistent syntax, how can I deal with such input?
@J.Doe it is not illegal syntax, it's basically not type safe (your map contains String -> Any). So in order to use it, you have to do type casting like 'asInstanceOf'. But it is generally more error prone, because compiler can't help you. I think, for your challenge it is ok to do it this way.
1

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]))

1 Comment

+1 since it's suggesting case class Node and l.map +1 since it was posted prior to mine -1 since it's suggesting .asInstanceOf to scala newcomer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.