Anton Ashanin
Anton Ashanin

Reputation: 1827

Scala: using foldl to add pairs from list to a map?

I am trying to add pairs from list to a map using foldl. I get the following error:

"missing arguments for method /: in trait TraversableOnce; follow this method with `_' if you want to treat it as a partially applied function"

code:

      val pairs = List(("a", 1), ("a", 2), ("c", 3), ("d", 4))

  def lstToMap(lst:List[(String,Int)], map: Map[String, Int] ) = {
    (map /: lst) addToMap ( _, _)
  }

  def addToMap(pair: (String, Int), map: Map[String, Int]): Map[String, Int] = {
      map + (pair._1 -> pair._2)
  }

What is wrong?

Upvotes: 0

Views: 1106

Answers (4)

pagoda_5b
pagoda_5b

Reputation: 7383

This is not a direct answer to the question, which is about folding correctly on the map, but I deem it important to emphasize that

  • a Map can be treated as a generic Traversable of pairs

and you can easily combine the two!

scala> val pairs = List(("a", 1), ("a", 2), ("c", 3), ("d", 4))
pairs: List[(String, Int)] = List((a,1), (a,2), (c,3), (d,4))

scala> Map.empty[String, Int] ++ pairs
res1: scala.collection.immutable.Map[String,Int] = Map(a -> 2, c -> 3, d -> 4)

scala> pairs.toMap
res2: scala.collection.immutable.Map[String,Int] = Map(a -> 2, c -> 3, d -> 4)

Upvotes: 1

Jed Wesley-Smith
Jed Wesley-Smith

Reputation: 4706

If you already have a collection of Tuple2s, you don't need to implement this yourself, there is already a toMap method that only works if the elements are tuples!

The full signature is:

def toMap[T, U](implicit ev: <:<[A, (T, U)]): Map[T, U]

It works by requiring an implicit A <:< (T, U) which is essentially a function that can take the element type A and cast/convert it to tuples of type (T, U). Another way of saying this is that it requires an implicit witness that A is-a (T, U). Therefore, this is completely type-safe.

Update: which is what @missingfaktor said

Upvotes: 1

Noah
Noah

Reputation: 13959

You need to swap the input values of addToMap and put it in parenthesis for this to work:

  def addToMap( map: Map[String, Int], pair: (String, Int)): Map[String, Int] = {
    map + (pair._1 -> pair._2)
  }

  def lstToMap(lst:List[(String,Int)], map: Map[String, Int] ) = {
    (map /: lst)(addToMap)
  }

missingfaktor's answer is much more concise, reusable, and scala-like.

Upvotes: 1

missingfaktor
missingfaktor

Reputation: 92116

scala> val pairs = List(("a", 1), ("a", 2), ("c", 3), ("d", 4))
pairs: List[(String, Int)] = List((a,1), (a,2), (c,3), (d,4))

scala> (Map.empty[String, Int] /: pairs)(_ + _)
res9: scala.collection.immutable.Map[String,Int] = Map(a -> 2, c -> 3, d -> 4)

But you know, you could just do:

scala> pairs.toMap
res10: scala.collection.immutable.Map[String,Int] = Map(a -> 2, c -> 3, d -> 4)

Upvotes: 10

Related Questions