2

给定一个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)

我想知道是否有一种更有效、可能更简单的方法来实现这一结果。

4

3 回答 3

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]()))
    }
  }
于 2014-08-17T10:10:22.510 回答
4

您走在正确的轨道上,但是您可以通过使用单个mapValues并结合mapand来简化一点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返回一个非严格的集合,这可能是也可能不是你想要的)。

于 2014-08-17T11:46:36.890 回答
0

@grotrianster 答案可以使用|+|Set 和 Map 的 Semigroup 二元运算来细化:

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
于 2014-10-24T23:02:30.443 回答