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)
现场示例: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)