tags:

views:

237

answers:

5

Hi all,

In Python, a dictionary can be constructed from an iterable collection of tuples:

>>> listOfTuples = zip(range(10), [-x for x in range(10)])
>>> listOfTuples
[(0, 0), (1, -1), (2, -2), (3, -3), (4, -4), (5, -5), (6, -6), (7, -7), (8, -8), (9, -9)]
>>> theDict = dict(listOfTuples)
>>> theDict
{0: 0, 1: -1, 2: -2, 3: -3, 4: -4, 5: -5, 6: -6, 7: -7, 8: -8, 9: -9}
>>> 

Is there an equivalent Scala syntax? I see that you can use a varargs type amount of Tuple2s to construct a map, e.g.

scala> val theMap = Map((0,0),(1,-1))
theMap: scala.collection.immutable.Map[Int,Int] = Map((0,0), (1,-1))

scala> theMap(0)
res4: Int = 0

scala> theMap(1)
res5: Int = -1

scala> val tuplePairs = List((0,0),(1,-1))
tuplePairs: List[(Int, Int)] = List((0,0), (1,-1))

scala> val mapFromIterable = Map(tuplePairs)
<console>:6: error: type mismatch;
 found   : List[(Int, Int)]
 required: (?, ?)
       val mapFromIterable = Map(tuplePairs)
                                 ^

I could loop through and assign each value manually, but it seems like there must be a better way.

scala> var theMap:scala.collection.mutable.Map[Int,Int] = scala.collection.mutable.Map()   
theMap: scala.collection.mutable.Map[Int,Int] = Map()

scala> tuplePairs.foreach(x => theMap(x._1) = x._2)                                     

scala> theMap
res13: scala.collection.mutable.Map[Int,Int] = Map((1,-1), (0,0))
+2  A: 

There are several options. First (but not recommmended, IMO), you can convert a List into a varargs using list:_* Alternatively, you can use something like the ++ function to add a list of values into a map (which is what Map.apply does anyways)

scala> (Map[Int,Int]()) ++ List((1,2),(3,4))
res4: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)

scala> Map(List((1,2),(3,4)):_*)
res5: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 3 -> 4)
Jackson Davis
Why are my maps printed as Map((1,-1), (0,0)) whereas yours go to the more pretty printed Map(1 -> -1, 0 -> 0)? Any idea?
I82Much
This works perfectly. Thanks.
I82Much
No clue, actually. Anyone else know? Hmm, this terminal is still 2.7.7, is that why?
Jackson Davis
+1  A: 

Look for methods toMap and zip in the iterable trait: http://www.scala-lang.org/docu/files/api/scala/collection/Iterable.html

Note that pretty much all collections implement this trait.

Daniel Ribeiro
+5  A: 

Using Scala 2.8.0 final, you can do it like this:


scala> val tuplePairs = List((0,0),(1,-1))
tuplePairs: List[(Int, Int)] = List((0,0), (1,-1))

scala> tuplePairs.toMap
res0: scala.collection.immutable.Map[Int,Int] = Map((0,0), (1,-1))

If you're using scala 2.7.7 you could do something like this, as an alternative to the method you used:


scala> val tuplePairs = List((0,0),(1,-1))
tuplePairs: List[(Int, Int)] = List((0,0), (1,-1))

scala> Map() ++ (tuplePairs map (t => (t._1,t._2)))
res2: scala.collection.immutable.Map[Int,Int] = Map(0 -> 0, 1 -> -1)

but as you can see, in 2.8.0 things have been much improved upon.

Arjan Blokzijl
toMap worked great. A lot clearer than the ++ syntax.
I82Much
The `map` in the 2.7 answer is unnecessary. `Map() ++ tuplePairs` would do, as would `Map(tuplePairs: _*)`.
Daniel
Indeed, you are right of course, thanks
Arjan Blokzijl
+1  A: 

While there are some answers that give good advice, here is what I think is closest to the original python code.

// Scala 2.8
val listOfTuples = (0 until 10) zip (for (x <- 0 until 10) yield -x)
val theMap = Map(listOfTuples:_*)

Scala 2.7 does not have zip on Ranges, yet, therefore you have to convert the Ranges to Lists in the first assignment:

// Scala 2.7
val listOfTuples = (0 until 10).toList zip (for (x <- 0 until 10) yield -x).toList
val theMap = Map(listOfTuples:_*)
mkneissl
+2  A: 

I cannot leave a comment to the accepted answer (not enough reputation yet), but the proposed solution for Scala 2.7 is overly complex:

scala> Map() ++ (tuplePairs map (t => (t._1,t._2)))
res2: scala.collection.immutable.Map[Int,Int] = Map(0 -> 0, 1 -> -1)

The "map" isn't doing anything, it's converting a Tuple2 into a Tuple2. This is enough:

scala> Map() ++ tuplePairs
res3: scala.collection.immutable.Map[Int,Int] = Map(0 -> 0, 1 -> -1)

In my eyes it would be even better to use Map.empty:

scala> Map.empty ++ tuplePairs
res4: scala.collection.immutable.Map[Int,Int] = Map(0 -> 0, 1 -> -1)
bse
Thanks for the info. I never would have found the ++ method.. how do you even search for that?
I82Much
Using ++ wasn't my idea, i just removed the unnecessary map. Unfortunately the 2.7 scaladocs seem to have been removed from scala-lang.org, but the ++ of a Map[A,B] is described there.
bse