23

Constructing scala.collection.Map from other collections, I constantly find myself writing:

val map = Map(foo.map(x=>(x, f(x)))

However, this doesn't really work since Map.apply takes variable arguments only - so I have to write:

val map = Map(foo.map(x=>(x, f(x)) toSeq :_*)

to get what I want, but that seems painful. Is there a prettier way to construct a Map from an Iterable of tuples?

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
themel
  • 8,825
  • 2
  • 32
  • 31

3 Answers3

34

Use TraversableOnce.toMap which is defined if the elements of a Traversable/Iterable are of type Tuple2. (API)

val map = foo.map(x=>(x, f(x)).toMap
Debilski
  • 66,976
  • 12
  • 110
  • 133
5

Alternatively you can use use collection.breakOut as the implicit CanBuildFrom argument to the map call; this will pick a result builder based on the expected type.

scala> val x: Map[Int, String] = (1 to 5).map(x => (x, "-" * x))(collection.breakOut)
x: Map[Int,String] = Map(5 -> -----, 1 -> -, 2 -> --, 3 -> ---, 4 -> ----)

It will perform better than the .toMap version, as it only iterates the collection once.

It's not so obvious, but this also works with a for-comprehension.

scala> val x: Map[Int, String] = (for (i <- (1 to 5)) yield (i, "-" * i))(collection.breakOut)
x: Map[Int,String] = Map(5 -> -----, 1 -> -, 2 -> --, 3 -> ---, 4 -> ----)
retronym
  • 54,768
  • 12
  • 155
  • 168
  • Thanks for this - while I'm not going to use it in code that other people have to read without pasting in links to the numerous explanations to the `CanBuildFrom` craziness, it *is* useful for the case where I want to convert an immutable range to a `mutable.Map`, where the answer I accepted before just gives me a type error. – themel Jul 01 '11 at 07:50
2
val map = foo zip (foo map f) toMap
Landei
  • 54,104
  • 13
  • 100
  • 195