如何使用Scala进行地图理解?

时间:2016-05-16 22:05:58

标签: scala dictionary-comprehension

使用Python,我可以做类似

的事情
listOfLists = [('a', -1), ('b', 0), ('c', 1)]
my_dict = {foo: bar for foo, bar in listOfLists}

my_dict == {'a': -1, 'b': 0, 'c': 1} => True

我知道这是字典理解。当我使用Scala查找此操作时,我发现this incomprehensible document(双关语)。

使用Scala是否有惯用的方法?

额外问题:我可以像my_dict = {foo: bar for foo, bar in listOfLists if bar > 0}一样使用此操作进行过滤吗?

3 个答案:

答案 0 :(得分:6)

首先,让我们解析你的Python代码,弄清楚它在做什么。

my_dict = {
  foo: bar       <-- Key, value names
  for foo, bar   <-- Destructuring a list
  in listOfLists <-- This is where they came from
}

所以你可以看到即使在这个非常简短的例子中,如果listOfLists实际上不是它所说的那样,那么实际上有很多冗余可能会失败。

如果listOfLists实际上是对的列表(键,值),那么在Scala中它是微不足道的:

listOfPairs.toMap

另一方面,如果它确实是列表,并且你想要取出第一个来制作密钥并将其余部分保存为值,那么它就像是

listOfLists.map(x => x.head -> x.tail).toMap

您可以使用collect来选择其中一些。例如,也许你只想要长度为2的列表(你可以if x.head > 0得到你的例子),在这种情况下你

listOfLists.collect{
  case x if x.length == 2 => x.head -> x.last
}.toMap

或者如果它实际上是List,您也可以

listOfLists.collect{
  case key :: value :: Nil => key -> value
}.toMap

答案 1 :(得分:3)

以下是一些例子:

val listOfLists = Vector(Vector(1,2), Vector(3,4), Vector(5,6))

val m1 = listOfLists.map { case Seq(a,b) => (a,b) }.toMap
val m2 = listOfLists.collect { case Seq(a,b) if b>0 => (a,b) }.toMap
val m3 = (for (Seq(a,b) <- listOfLists) yield (a,b)).toMap
val m4 = (for (Seq(a,b) <- listOfLists if b>0) yield (a,b)).toMap

val m5 = Map(listOfLists.map { case Seq(a,b) => (a,b) }: _*)
val m6 = Map(listOfLists.collect { case Seq(a,b) => (a,b) }: _*)
val m7 = Map((for (Seq(a,b) <- listOfLists) yield (a,b)): _*)
val m8 = Map((for (Seq(a,b) <- listOfLists if b>0) yield (a,b)): _*)

您可以使用Map.toMap创建Map(xs: _*)collect方法可让您按map进行过滤。并且for-comprehension使用与您的示例最相似的语法。

答案 2 :(得分:3)

我将在Scala2.x和Python 3.x

中比较list comprehension

<强> 1。序列

在python中:

xs = [x*x for x in range(5)]
#xs = [0, 1, 4, 9, 16]

ys = list(map(lambda x: x*x, range(5)))
#ys = [0, 1, 4, 9, 16]

在Scala中:

scala> val xs = for(x <- 0 until 5) yield x*x
xs: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16)

scala> val ys = (0 until 5) map (x => x*x)
ys: scala.collection.immutable.IndexedSeq[Int] = Vector(0, 1, 4, 9, 16)

或者你真的想要列表

scala> import collection.breakOut

scala> val xs: List[Int] = (for(x <- 0 until 5) yield x*x)(breakOut)
xs: List[Int] = List(0, 1, 4, 9, 16)

scala> val ys: List[Int] = (0 until 5).map(x => x*x)(breakOut)
ys: List[Int] = List(0, 1, 4, 9, 16)

scala> val zs = (for(x <- 0 until 5) yield x*x).toList
zs: List[Int] = List(0, 1, 4, 9, 16)

<强> 2。设置

在Python中

s1 = { x//2 for x in range(10) }
#s1 = {0, 1, 2, 3, 4}
s2 = set(map(lambda x: x//2, range(10)))
#s2 = {0, 1, 2, 3, 4}

在Scala中

scala> val s1 = (for(x <- 0 until 10) yield x/2).toSet
s1: scala.collection.immutable.Set[Int] = Set(0, 1, 2, 3, 4)

scala> val s2: Set[Int] = (for(x <- 0 until 10) yield x/2)(breakOut)
s2: Set[Int] = Set(0, 1, 2, 3, 4)

scala> val s3: Set[Int] = (0 until 10).map(_/2)(breakOut)
s3: Set[Int] = Set(0, 1, 2, 3, 4)

scala> val s4 = (0 until 10).map(_/2).toSet
s4: scala.collection.immutable.Set[Int] = Set(0, 1, 2, 3, 4)

第3。字典

在Python中:

pairs = [(1, 'a'), (2, 'b'), (3, 'c'), (4, 'd')]
#d1 = {1: 'aa', 2: 'bb', 3: 'cc', 4: 'dd'}

d2 = dict([(k*2, v) for k, v in pairs])
#d2 = {2: 'a', 4: 'b', 6: 'c', 8: 'd'}

在Scala中

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

scala> val d1 = (for((k, v) <- pairs) yield (k, v*2)).toMap
d1: scala.collection.immutable.Map[Int,String] = Map(1 -> aa, 2 -> bb, 3 -> cc, 4 -> dd)

scala> val d2 = Map(pairs map { case(k, v) => (k*2, v) } :_*)
d2: scala.collection.immutable.Map[Int,String] = Map(2 -> a, 4 -> b, 6 -> c, 8 -> d)

scala> val d3 = pairs map { case(k, v) => (k*2, v) } toMap
d3: scala.collection.immutable.Map[Int,String] = Map(2 -> a, 4 -> b, 6 -> c, 8 -> d)

scala> val d4: Map[Int, String] = (for((k, v) <- pairs) yield (k, v*2))(breakOut)
d4: Map[Int,String] = Map(1 -> aa, 2 -> bb, 3 -> cc, 4 -> dd)