Devo creare un nuovo oggetto da mescolare in un tratto Scala?
Domanda
In Scala, chiamare groupBy ()
su una raccolta restituisce una Mappa
dove i valori sono raccolte, ma voglio un MultiMap
. Qual è il modo più semplice per eseguire la conversione? Posso evitare di creare un nuovo MultiMap
e di copiare tutto?
Soluzione
Penso che la risposta a " Devo creare un nuovo oggetto da mescolare in un tratto Scala? " è " Sì " ;. Puoi ridurre al minimo il dolore con il wrapping di oggetti e conversioni implicite.
Per il tuo problema specifico, non sono stato in grado di forzare groupBy (...) per restituire una mappa mutabile in set mutabili, che dovresti avvolgere con "MapProxy con MultiMap". Ma non sono troppe righe di codice per implementare la tua versione di " groupBy " ;:
package blevins.example
object App extends Application {
implicit def multiMapable[B](c: Iterable[B]) = new {
def groupByMM[A](f: B => A) = {
import scala.collection.mutable._
val ret = new HashMap[A,Set[B]] with MultiMap[A,B]
for (e <- c) { ret.addBinding(f(e), e) }
ret
}
}
val c = List(1,2,3,4,5,6,7,8,9)
val mm = c.groupByMM { i => if (i < 5) "alpha" else "beta" }
mm.addBinding("alpha",12)
println(mm) // Map(beta -> Set(5, 7, 6, 9, 8), alpha -> Set(3, 1, 4, 2, 12))
}
Addendum
Ecco un esempio del wrapping di una mappa esistente [String, Set [Int]] in una MultiMap senza copiare i valori:
object App extends Application {
import scala.collection.mutable._
val seed: Map[String,Set[Int]] = Map("even" -> Set(2,4,6), "odd" -> Set(1,3,5))
val multiMap = new MapProxy[String,Set[Int]] with MultiMap[String,Int] {
val self = seed
}
multiMap.addBinding("even", 8)
println(multiMap) // Map(odd -> Set(5, 3, 1), even -> Set(6, 8, 4, 2))
}
Nota che questo non può essere fatto sul risultato di groupBy (...) perché la mappa seme deve essere mutabile e groupBy (...) restituisce una mappa immutabile.