Должен ли я создавать новый объект для смешивания с признаком Scala?
Вопрос
В Scala, вызывая groupBy()
в коллекции возвращает Map
где значения являются коллекциями, но я хочу MultiMap
.Какой самый простой способ выполнить преобразование?Могу ли я избежать создания нового MultiMap
и все переписывать заново?
Решение
Я думаю, что ответ на вопрос "Должен ли я создать новый объект для смешивания в черте Scala?" - "Да".Вы можете немного свести к минимуму неудобства с помощью обертывания объектов и неявных преобразований.
Для вашей конкретной проблемы я не смог принудить groupBy (...) вернуть изменяемую карту в изменяемые наборы, для чего вам нужно было бы обернуть ее "MapProxy with MultiMap".Но для реализации вашей собственной версии "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))
}
Добавление
Вот пример переноса существующей карты[String,Set[Int]] в МУЛЬТИМАП без копирования значений:
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))
}
Обратите внимание, что это не может быть сделано для результата groupBy(...), потому что начальная карта должна быть изменяемой, а groupBy(...) возвращает неизменяемую карту.