给出Seq
个元组,如:
Seq(
("a",Set(1,2)),
("a",Set(2,3)),
("b",Set(4,6)),
("b",Set(5,6))
)
我想groupBy
然后flatMap
获取类似值:
Map(
b -> Set(4, 6, 5),
a -> Set(1, 2, 3)
)
我的第一个实现是:
Seq(
("a" -> Set(1,2)),
("a" -> Set(2,3)),
("b" -> Set(4,6)),
("b" -> Set(5,6))
) groupBy (_._1) mapValues (_ map (_._2)) mapValues (_.flatten.toSet)
我想知道是否有更有效,也许更简单的方法来实现这一结果。
答案 0 :(得分:4)
我会使用foldLeft,我认为它更具可读性,你可以避免使用groupBy
val r = Seq(
("a",Set(1,2)),
("a",Set(2,3)),
("b",Set(4,6)),
("b",Set(5,6))
).foldLeft(Map[String, Set[Int]]()){
case (seed,(k,v)) => {
seed.updated(k,v ++ seed.getOrElse(k,Set[Int]()))
}
}
答案 1 :(得分:4)
您走在正确的轨道上,但您可以使用一个mapValues
并结合map
和flatten
来简化一点:
val r = Seq(
("a" -> Set(1,2)),
("a" -> Set(2,3)),
("b" -> Set(4,6)),
("b" -> Set(5,6))
).groupBy(_._1).mapValues(_.flatMap(_._2).toSet)
我实际上发现这比foldLeft
版本更具可读性(但请注意mapValues
会返回a non-strict collection,这可能是您想要的,也可能不是。“
答案 2 :(得分:0)
@grotrianster回答可以使用Set和Map的半群二进制运算|+|
进行优化:
import scalaz.syntax.semigroup._
import scalaz.std.map._
import scalaz.std.set._
Seq(
("a",Set(1,2)),
("a",Set(2,3)),
("b",Set(4,6)),
("b",Set(5,6))
).foldLeft(Map[String, Set[Int]]()){case (seed, (k, v)) => seed |+| Map(k -> v)}
使用reduce
代替fold
:
Seq(
("a", Set(1, 2)),
("a", Set(2, 3)),
("b", Set(4, 6)),
("b", Set(5, 6))
).map(Map(_)).reduce({_ |+| _})
将Set
和Map
视为Monoids:
Seq(
("a", Set(1, 2)),
("a", Set(2, 3)),
("b", Set(4, 6)),
("b", Set(5, 6))
).map(Map(_)).toList.suml