Eu tenho que criar um novo objeto de misturar em um traço Scala?
Pergunta
Em Scala, chamando groupBy()
em uma coleção retorna uma Map
onde os valores são coleções, mas eu quero uma MultiMap
. Qual é a maneira mais fácil de fazer a conversão? Posso evitar a criação de um novo MultiMap
e copiar tudo de novo?
Solução
Eu acho que a resposta à pergunta "Eu tenho que criar um novo objeto para misturar em uma Scala traço?" é sim". Você pode minimizar a dor alguma com objetos de acondicionamento e conversões implícitas.
Para o seu problema específico, eu era incapaz de coagir groupBy (...) para retornar um mapa mutável para conjuntos mutáveis, o que você precisa para envolvê-lo com "MapProxy com MultiMap". Mas, não é muitas linhas de código para implementar sua própria versão de "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))
}
Adenda
Aqui está um exemplo de envolver um já existente Mapa [String, Set [Int]] em um MultiMap sem copiar os valores:
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))
}
Note que isso não pode ser feito sobre o resultado da groupBy (...) porque o mapa semente é necessário para ser mutável e groupBy (...) retorna um mapa imutável.