00.scala2014. 3. 28. 13:36
반응형

Scala Map FAQ: How can I iterate/loop over a Scala Map?

There are several different ways to iterate over a Scala Map, and the method you choose depends on the problem you need to solve.

To get started with our examples, let's create a simple Map we can work with:

scala> val m1 = Map("fname" -> "Al", "lname" -> "Alexander")

Iterating over Scala maps

Once you have a Map, you can iterate over it using several different techniques. For me, this is by far the easiest technique:

scala> for ((k,v) <- m1) printf("key: %s, value: %s\n", k, v)
key: fname, value: Al
key: lname, value: Alexander

This page has some other Map and for loop examples, which I've reproduced here:

// version 1 (tuples)
m1 foreach (x => println (x._1 + "-->" + x._2))

// version 2 (foreach and case)
m1 foreach {case (key, value) => println (key + "-->" + value)}

You can choose whatever format you prefer. Scala is beginning to remind me of the Perl slogan: "There's more than one way to do it", and this is good, because you can choose whichever approach makes the most sense for the problem at hand.

Scala Map, keys, foreach, and tuples

To demonstrate a more "real world" example of looping over a Scala Map, while working through some programming examples in the book, Programming Collective Intelligence, I decided to code them up in Scala, and I wanted to share the approaches I prefer using the Scala foreach and for loops.

To begin with, I defined my Scala Map like this:

val p1Ratings = Map("Lady in the Water"-> 3.0, 
                    "Snakes on a Plane"-> 4.0,
                    "You, Me and Dupree"-> 3.5)

In my case, when I'm iterating over the Map I'm really just interested in the Map keys, so the cleanest way to loop over every Map element is like this:

p1Ratings.keys.foreach( (movie) => 
  if (p2Ratings.contains(movie)) similarItems += (movie -> true)
)

While I chose that looping method in my code, I could also use the "tuples" approach, where movie is a Tuple, and I only use the first element of the Tuple, which happens to be my keys:

p1Ratings foreach ( (movie) => 
  if (p2Ratings.contains(movie._1)) similarItems += (movie._1 -> true)
)

In that approach, I ignore the second element of each Tuple, because I don't need it. (Which is why I don't like this approach for this instance.)

In a similar approach, I loop over the Map as shown next, creating a field named rating1 which I again don't use because I don't need it:

for ((movie1, rating1) <- p1Ratings) {
  if (p2Ratings.contains(movie1)) similarItems += (movie1 -> true)
}

These last two approaches will work better, and look a little more logical, if you need to access the key and value for each map element, but in my case, since I don't need to values, I'm using the first approach shown above.

Posted by 1010