在 Scala 中以函数式方式反转 MultiMap

Invert MultiMap in functional way in Scala

在 Scala 中,如果我们有一个将 String 映射到 Set[String] 的 MultiMap,例如:

val a = Map(
  "Account1" -> Set("Cars", "Trucks"),
  "Account2" -> Set("Trucks", "Boats")
)

什么是反转/反转它以结束的优雅方式:

Map(
  "Boats" -> Set("Account2"),
  "Cars" -> Set("Account1"),
  "Trucks" -> Set("Account1", "Account2")
)

对不起,长线,你可以分解它,这只是一个快速而肮脏的解决方案,但它确实有效

scala> a.toList.flatMap{ case (k,v:Set[_]) => v map (x => (x,k))}.groupBy(_._1).map{ case (k,v:List[(String,String)]) => (k,v.map(_._2).toSet)} 
res45: scala.collection.immutable.Map[String,scala.collection.immutable.Set[String]] = Map(Boats -> Set(Account2), Trucks -> Set(Account1, Account2), Cars -> Set(Account1))

或者如果您更喜欢可读版本(与上面相同,只是细分为行):) :

scala> val aTuples =  a.toList.flatMap{ case (k,v:Set[_]) => v map (x => (x,k))}
aTuples: List[(String, String)] = List((Cars,Account1), (Trucks,Account1), (Trucks,Account2), (Boats,Account2))

scala> val grouped = aTuples.groupBy(_._1)
grouped: scala.collection.immutable.Map[String,List[(String, String)]] = Map(Boats -> List((Boats,Account2)), Trucks -> List((Trucks,Account1), (Trucks,Account2)), Cars -> List((Cars,Account1)))

scala> val flattenAndToSet = grouped.map{ case (k,v:List[(String,String)]) => (k,v.map(_._2).toSet)}
flattenAndToSet: scala.collection.immutable.Map[String,scala.collection.immutable.Set[String]] = Map(Boats -> Set(Account2), Trucks -> Set(Account1, Account2), Cars -> Set(Account1))