展平集合的地图

时间:2014-09-17 01:15:14

标签: scala

我试图在一个可以穿越的地图上展平地图,意思是:

Map( Set(1, 2, 3) -> 'A', Set(4, 5, 6) -> 'B')

应该扁平化:

Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)

这是我做的:

def fuse[A, B, T <: Traversable[A]](mapOfTravs: Map[T, B]): Map[A, B] = {
  val pairs = for {
    trav <- mapOfTravs.keys
    key <- trav
  } yield (key, mapOfTravs(trav))
  pairs.toMap
}   

有效。但是:

  1. 有更简单的方法吗?

  2. 我对Scala类型系统不太满意,我确信这可以改进。每当我使用我的函数时,我必须明确指定类型:

    val map2 = Map( Set(1, 2, 3) -> 'A', Set(4, 5, 6) -> 'B')
    val fused2 = fuse[Int, Char, Set[Int]](map2)
    
    val map1: Map[Traversable[Int], Char] = Map( Set(1, 2, 3) -> 'A', Set(4, 5, 6) -> 'B')
    val fused1 = fuse[Int, Char, Traversable[Int]](map1)
    
  3. P.S。:当密钥遍历具有非空交集时,此fuse函数没有多大意义。

4 个答案:

答案 0 :(得分:4)

这基本上就是你在理解中所做的,但简化了一点:

  def fuse[A, B, T <: Traversable[A]](mapOfTravs: Map[T, B]): Map[A, B] = {
    mapOfTravs.flatMap({ case (s, c) => s.map(i => i -> c) })
  }

你可以对这些类型做的不多,我确定你可以做一些类型的lambda shenanigans,我只是不确定如何做...

<强>更新 这里的版本略好一些,与上面的flatMap相同:

  def fuse2[A, B, T <: Traversable[A]](mapOfTravs: Map[T, B]): Map[A, B] = {
    for {
      (keys, value) <- mapOfTravs
      key <- keys
    } yield key -> value
  }

答案 1 :(得分:2)

就像@Azzie一样,我在想拉链,但也许Azzie有这些优点。

scala> val m = Map( Set(1, 2, 3) -> 'A', Set(4, 5, 6) -> 'B')
m: scala.collection.immutable.Map[scala.collection.immutable.Set[Int],Char] = Map(Set(1, 2, 3) -> A, Set(4, 5, 6) -> B)

scala> (m map { case (k, v) => k zip (Stream continually v) }).flatten.toMap
res0: scala.collection.immutable.Map[Int,Char] = Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)

scala> (m map { case (k, v) => k zipAll (Nil, null, v) }).flatten.toMap
res1: scala.collection.immutable.Map[Any,Char] = Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)

scala> m flatMap { case (k, v) => k zip (Stream continually v) }
res2: scala.collection.immutable.Map[Int,Char] = Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)

如何很好地概括它并不明显。

答案 2 :(得分:1)

这看起来很可怕,使用0是一种作弊,但它可以完成这项工作

 m.map( {case (s,c) => s.zipAll(Set(c),0,c)} ).flatten.toMap

答案 3 :(得分:1)

因为我显然是在&#34;可怕的通用含义&#34;踢lately

import scala.collection.MapLike
import scala.collection.TraversableLike
import scala.collection.generic.CanBuildFrom

implicit class Map_[
  A,
  B,
  T1 : ({type L[X] = X => TraversableLike[A, T2]})#L,
  T2,
  M1 : ({type L[X] = X => MapLike[T1, B, M2]})#L, 
  M2 <: MapLike[T1, B, M2] with Map[T1, B]
](map: M1) {

  def fuse[M3](implicit cbfM: CanBuildFrom[M2, (A, B), M3]) : M3 =
    map.flatMap({ case (k, v) => k.toTraversable.map((_, v)) })
}

示例:

scala> Map(Set(1, 2, 3) -> 'A', Set(4, 5, 6) -> 'B').fuse
res: scala.collection.immutable.Map[Int,Char] =
     Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)

scala> Map(Array(1, 2, 3) -> 'A', Array(4, 5, 6) -> 'B').fuse
res: scala.collection.immutable.Map[Int,Char] =
     Map(5 -> B, 1 -> A, 6 -> B, 2 -> A, 3 -> A, 4 -> B)