Scala groupBy+地图问题

Scala groupBy+map issue

现场示例:Scastie Example

我不明白这是怎么回事。我有一个这样的元组序列:

val v = Seq(
  ("provider@test.com",2), 
  ("consumer@test.com",2), 
  ("provider@test.com",9), 
  ("provider@test.com",10)
)

我想这样分组:

v.groupBy{ case(email, id) => id }

这导致:

Map(
  2 -> List(
      (provider@test.com,2),
      (consumer@test.com,2)
  ), 
  10 -> List(
      (provider@test.com,10)
  ), 
  9 -> List(
      (provider@test.com,9)
  )
)

这很有道理,但现在如果我像这样再次映射它们:

v.groupBy{ case(email, id) => id}.map{case(id, data) => data.head}.toSeq

我希望结果是:

Vector((provider@test.com,2), (provider@test.com,10), (provider@test.com,9))

然而我得到:

Vector((provider@test.com,9))

怎么了?

这确实有点令人费解。发生这种情况是因为 Map[K, V] 上的 map 也是 returns 一对 Map[K', V'],并且因为您的密钥都是相同的(邮寄地址),所以您只能返回一个值。

这可以通过使用 .values 来避免,其中 returns Iterable Map 中的值,然后 .map:

v
 .groupBy { case (_, id) => id }
 .values
 .map(_.head)
 .toList

当您执行 groupBy 时,您会得到一个 Map[Int, Seq[(String, Int)]]map 方法将对 Map[Int, Seq[(String, Int)]] 中的每个条目进行操作。如果你只是想对你可以做的值进行操作

v.groupBy{ case(email, id) => id}.mapValues(...

当您不小心在 Map 上调用 map 时,就会发生这种情况。 在这种情况下,对

  2 -> List(
      (provider@test.com,2),
      (consumer@test.com,2)
  ), 
  10 -> List(
      (provider@test.com,10)
  ), 
  9 -> List(
      (provider@test.com,9)
  )

转化成对

(provider@test.com,2)
(provider@test.com,10)
(provider@test.com,9)

然后再次插入到新构造的映射中,用 10 覆盖值 2,然后用 9 覆盖值。最终结果是具有单个条目 (provider@test.com,9) 的类型 Map[String, Int] 的映射,即当然不是你想要的。

改为这样做:

println(v.groupBy{ case(email, id) => id}.toSeq.map{case(id, data) => data.head})

这是错误的,因为您在 Map 对象上调用了 map 方法,正如 Andrey Tyukin 已经指出的那样。先将其转换为列表,然后应用具有适当转换函数的 map 方法,如下所示:
这个有效:

 v.groupBy{ case(email, id) => id}.toList.map(_._2.head)