2013-11-26 2 views
14

私はScala construct map(f).flatten was equivalent to flatMap(f)と考えました。しかし、この例ではそうではありません。私はそれでケースクラスの役割が何であるのだろうか。整数を使用する場合、どちらも同等です。しかし、私の場合、私はできません。フラットマップフラットマップは同等ではありません

case class CTest(v: Int) 
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2))) 
val possibilities = s flatMap { m => 
    val mapping = m flatMap { 
    case (label, destNodes) => destNodes map { 
     case nodes => (label, nodes) } 
    } 
    mapping 
} 
possibilities 

case class CTest(v: Int) 
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2))) 
val possibilities = s flatMap { m => 
    val mapping = m map { 
    case (label, destNodes) => destNodes map { 
     case nodes => (label, nodes) } 
    } 
    mapping.flatten 
} 
possibilities 

利回り

Set((CTest(0),0), (CTest(0),3), (CTest(1),0), (CTest(1),2)) 

任意のアイデアなぜ一方

Set((CTest(0),3), (CTest(1), 2)) 

が得?

答えて

7

flatMapの実装を見てみましょう:flatMap

def flatMap[B, That](f: A => GenTraversableOnce[B])(implicit bf: CanBuildFrom[Repr, B, That]): That = { 
    def builder = bf(repr) // extracted to keep method size under 35 bytes, so that it can be JIT-inlined 
    val b = builder 
    for (x <- this) b ++= f(x).seq 
    b.result 
} 

結果は、関数fのオリジナルコレクション型と結果のタイプによって異なります。最初の例では、マップからタプルのシーケンスを生成するので、コンパイラは同じキーを上書きするMapのビルダーを提供するCanBuildFrom[Map[A, B], (C, D), Map[C, D]]のような実装を選択します。

あなたが直接あなたが望む結果が得られますよう、無地のiterableにマップを変換することができます:

case class CTest(v: Int) 
val s = Set(Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2))) 
val possibilities = s flatMap { m => 
    val mapping = m.toIterable.flatMap { 
    case (label, destNodes) => destNodes map { 
     case nodes => (label, nodes) } 
    } 
    mapping 
} 
possibilities 
10

これは、中間データ構造のために発生します。

私はあなたの例の簡単なバージョンを取るつもりです。

val m = Map(CTest(0) -> List(0, 3), CTest(1) -> List(0, 2)) 

Map(CTest(0), 0)(CTest(1), 0)のキーの一意性のために、あなたはここで直接にMap[CTest, Int]

scala> m flatMap { 
|  case (label, destNodes) => destNodes map { 
|  case nodes => (label, nodes) } 
| } 
res3: scala.collection.immutable.Map[CTest,Int] = Map(CTest(0) -> 3, CTest(1) -> 2) 

を作成flatMapを使用して結果から削除されます。 flatMapがセットされている場合、MapにあるTuplesSetが得られます。

2番目の例では、マップして平坦化します。

val mapping = m map { 
|  case (label, destNodes) => destNodes map { 
|  case nodes => (label, nodes) } 
| } 
mapping: scala.collection.immutable.Iterable[List[(CTest, Int)]] = List(List((CTest(0),0), (CTest(0),3)), List((CTest(1),0), (CTest(1),2))) 

mapping.flatten 
res4: scala.collection.immutable.Iterable[(CTest, Int)] = List((CTest(0),0), (CTest(0),3), (CTest(1),0), (CTest(1),2)) 

任意のMapまたはプロセスの途中で作成された別の一意性、保存データ構造はありません。したがって、値は削除されません。

関連する問題