In Scala, calling groupBy()
on a collection returns a Map
where the values are collections, but I want a MultiMap
. What's the easiest way to do the conversion? Can I avoid creating a new MultiMap
and copying everything over?
Traits are similar in spirit to interfaces in Java programming language. Unlike a class, Scala traits cannot be instantiated and have no arguments or parameters. However, you can inherit (extend) them using classes and objects.
Defining a Trait for Common Behavior We create a trait object by specifying some sort of pointer, such as a & reference or a Box<T> smart pointer, then the dyn keyword, and then specifying the relevant trait.
In scala, trait is a collection of abstract and non-abstract methods. You can create trait that can have all abstract methods or some abstract and some non-abstract methods. A variable that is declared either by using val or var keyword in a trait get internally implemented in the class that implements the trait.
Mixins are traits which are used to compose a class. Scala 2.
I think the answer to "Do I have to create a new object to mix in a Scala trait?" is "Yes". You can minimize the pain some with wrapping objects and implicit conversions.
For your specific problem, I was unable to coerce groupBy(...) to return a mutable map to mutable sets, which you would need to wrap it with "MapProxy with MultiMap". But, it is not too many lines of code to implement your own version of "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
Here is an example of wrapping an existing Map[String,Set[Int]] into a MultiMap without copying the values:
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 that this cannot be done on the result of groupBy(...) because the seed map is required to be mutable and groupBy(...) returns an immutable map.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With