Scala multimap: get item or else empty set - scala

if I'm using the Scala Multimap, and I want to get the values associated with a key or else the empty set, do I have to write the following?
multimap.getOrElse("key", new collection.mutable.HashSet())
It would seem that the following should just work. An empty set seems like a good default value.
multimap.getOrElse("key")

Normally you would use Map.withDefaultValue for this. However, it looks as if you can't really get this behavior and still have a collection typed as a MultiMap[A, B]. The return type of MultiMap.withDefaultValue is Map[A, Set[B]]. So unfortunately you'll have to abandon the use of the MultiMap mixin to get the behavior you desire.

As you observed, the MultiMap trait doesn't do what you want. However, you can add a default value yourself if the Map is specifically mutable or immutable. Here's an example,
scala> val m = collection.mutable.Map(1 -> 2)
m: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)
scala> val m2 = m.withDefaultValue(42)
m2: scala.collection.mutable.Map[Int,Int] = Map(1 -> 2)
scala> m2(1)
res0: Int = 2
scala> m2(2)
res1: Int = 42
Strangely, the above won't work if the type of m is an abstract collection.Map. The comment in the source code says this is due to variance issues.

The withDefaultValue can be use for this use case. For instance:
import collection.mutable._
val multimap = Map[String, HashSet[String]]() withDefaultValue(new HashSet())
scala> multimap("key")
// res1: scala.collection.mutable.HashSet[String] = Set()

Since, as Garrett Rowe noted, withDefaultValue doesn't preserve the proper MultiMap type when using the mixin, you can instead override the default method in an anonymous class and preserve the behavior of MultiMap:
scala> import collection.mutable.{ HashMap, MultiMap, Set }
import collection.mutable.{HashMap, MultiMap, Set}
scala> val map: MultiMap[String, Int] = new HashMap[String, Set[Int]] with MultiMap[String, Int] {
| override def default(key: String): Set[Int] = Set.empty[Int]
| }
map: scala.collection.mutable.MultiMap[String,Int] = Map()
scala> map("foo")
res0: scala.collection.mutable.Set[Int] = Set()
scala> map.addBinding("foo", 1)
res1: map.type = Map(foo -> Set(1))
scala> map("foo")
res2: scala.collection.mutable.Set[Int] = Set(1)

Related

Why do `scala.collection.mutable.Map`s `withDefaultValue`s not properly retain default values?

What is happening here?
Welcome to Scala 2.13.5 (OpenJDK 64-Bit Server VM, Java 1.8.0_312).
...
> import scala.collection.mutable.{Map => MMap, ListBuffer => MList}
import scala.collection.mutable.{Map=>MMap, ListBuffer=>MList}
> val m = MMap[String, MList[String]]().withDefaultValue(MList[String]())
val m: scala.collection.mutable.Map[String,scala.collection.mutable.ListBuffer[String]] = Map()
> m("a")
val res0: scala.collection.mutable.ListBuffer[String] = ListBuffer()
> m("a").addOne("b")
val res1: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
> m
val res2: scala.collection.mutable.Map[String,scala.collection.mutable.ListBuffer[String]] = Map()
> m.keys
val res3: Iterable[String] = Set()
> m("a")
val res4: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
some of the text above has been removed for readability
Because your default value is mutable, you just mutated the default value. But you never inserted anything in the Map that is why you don't see anything inside.
m("a") is syntactic sugar for m.apply("a") which since there is no value for that key, but there is a default value set, it results in the default value you just set earlier.
If you'll check the withDefaultValue doc, you'll see this:
The same map with a given default value. Note: The default is only
used for apply. Other methods like get, contains, iterator, keys, etc.
are not affected by withDefaultValue. Invoking transformer methods
(e.g. map) will not preserve the default value.
Since ListBuffer is mutable you are directly mutating the contents of the default value, when using the addOne method on it.
So now every key that has no value in the Map will result in ListBuffer(b):
scala> m("a")
val res1: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
scala> m("c")
val res2: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
scala> m("whatever")
val res3: scala.collection.mutable.ListBuffer[String] = ListBuffer(b)
You should use an immutable List as the default value if you want it to remain unchanged.

Scala - Iterate over an Iterator of type Product[K,V]

I am a newbie to Scala and I am trying to understand collectives. I have a sample Scala code in which a method is defined as follows:
override def write(records: Iterator[Product2[K, V]]): Unit = {...}
From what I understand, this function is passed an argument record which is an Iterator of type Product2[K,V]. Now what I don't understand is this Product2 a user defined class or is it a built in data structure. Moreover how do explore the key-value pair contents of Product2 and how do I iterate over them.
Chances are Product2 is a built-in class and you can easily check it if you're in modern IDE (just hover over it with ctrl pressed), or, by inspecting file header -- if there is no related imports, like some.custom.package.Product2, it's built-in.
What is Product2 and where it's defined? You can easily found out such things by utilizing Scala's ScalaDoc:
In case of build-in class you can treat it like tuple of 2 elements (in fact Tuple2 extends Product2, as you may see below), which has ._1 and ._2 accessor methods.
scala> val x: Product2[String, Int] = ("foo", 1)
// x: Product2[String,Int] = (foo,1)
scala> x._1
// res0: String = foo
scala> x._2
// res1: Int = 1
See How should I think about Scala's Product classes? for more.
Iteration is also hassle free, for example here is the map operation:
scala> val xs: Iterator[Product2[String, Int]] = List("foo" -> 1, "bar" -> 2, "baz" -> 3).iterator
xs: Iterator[Product2[String,Int]] = non-empty iterator
scala> val keys = xs.map(kv => kv._1)
keys: Iterator[String] = non-empty iterator
scala> val keys = xs.map(kv => kv._1).toList
keys: List[String] = List(foo, bar, baz)
scala> xs
res2: Iterator[Product2[String,Int]] = empty iterator
Keep in mind though, that once iterator was consumed, it transitions to empty state and can't be re-used again.
Product2 is just two values of type K and V.
use it like this:
write(List((1, "one"), (2, "two")))
the prototype can also be written like: override def write(records: Iterator[(K, V)]): Unit = {...}
To access values k of type K and v of type V.
override def write(records: Iterator[(K, V)]): Unit = {
records.map{case (k, v) => w(k, v)}
}

How to write asInstanceOfOpt[T] where T <: Any

There's a handy implementation of asInstanceOfOpt, a safe version of asInstanceOf, given in the answer to How to write "asInstanceOfOption" in Scala. It appears that, Scala 2.9.1, this solution now only works with AnyRef:
class WithAsInstanceOfOpt(obj: AnyRef) {
def asInstanceOfOpt[B](implicit m: Manifest[B]): Option[B] =
if (Manifest.singleType(obj) <:< m)
Some(obj.asInstanceOf[B])
else
None
}
Can this be rewritten to support Any?
If you look in the Scala API the function singleType takes a parameter of type AnyRef. I don't really know the background for this decision, but it seems you need to work around it. Instead of using the method singleType I'd suggest using the classType method which basically can make a manifest for any class. It'll take a bit more code, but it could look something like this:
class WithAsInstanceOfOpt(obj : Any) {
def asInstanceOfOpt[B : Manifest] : Option[B] = // [B : Manifest] is shorthand for [B](implicit m : Manifest[B])
if (Manifest.classType(manifest, obj.getClass) <:< manifest)
Some(obj.asInstanceOf[B])
else None
}
You could use shapeless's Typeable from Miles Sabin:
Type casting using type parameter
It handles primitives and boxing:
scala> import shapeless._; import syntax.typeable._
import shapeless._
import syntax.typeable._
scala> 1.cast[Int]
res1: Option[Int] = Some(1)
scala> 1.cast[String]
res2: Option[String] = None
scala> "hello".cast[String]
res4: Option[String] = Some(hello)
scala> "foo".cast[Int]
res5: Option[Int] = None
You can see the source here to see how it's written:
https://github.com/milessabin/shapeless/blob/master/core/src/main/scala/shapeless/typeable.scala
Here's working code for 2.9.x. It will give deprecation warnings for 2.10.x, but using ClassTag instead of Manifest and runtimeClass instead of erasure will fix them.
//Precondition: classS must have been produced through primitiveToBoxed, because v will be boxed.
def ifInstanceOfBody[T, S](v: T, classS: Class[_]): Option[S] = {
if (v == null || !classS.isInstance(v))
None
else
Some(v.asInstanceOf[S])
}
object ClassUtil {
import java.{lang => jl}
private val primitiveToBoxedMap = Map[Class[_], Class[_]](
classOf[Byte] -> classOf[jl.Byte],
classOf[Short] -> classOf[jl.Short],
classOf[Char] -> classOf[jl.Character],
classOf[Int] -> classOf[jl.Integer],
classOf[Long] -> classOf[jl.Long],
classOf[Float] -> classOf[jl.Float],
classOf[Double] -> classOf[jl.Double],
classOf[Boolean] -> classOf[jl.Boolean],
classOf[Unit] -> classOf[jl.Void]
)
def primitiveToBoxed(classS: Class[_]) =
primitiveToBoxedMap.getOrElse(classS, classS)
}
class IfInstanceOfAble[T](v: T) {
def asInstanceOfOpt[S](implicit cS: Manifest[S]): Option[S] =
ifInstanceOfBody[T, S](v, ClassUtil.primitiveToBoxed(cS.erasure))
}
implicit def pimpInstanceOf[T](t: T) = new IfInstanceOfAble(t)
Testing results:
scala> 1.asInstanceOfOpt[Int]
res9: Option[Int] = Some(1)
scala> "".asInstanceOfOpt[String]
res10: Option[String] = Some()
scala> "foo".asInstanceOfOpt[String]
res11: Option[String] = Some(foo)
scala> 1.asInstanceOfOpt[String]
res12: Option[String] = None
scala> "".asInstanceOfOpt[Int]
res13: Option[Int] = None
The code is slightly more verbose than needed here, mostly because I took it from an existing codebase of mine where I reuse ifInstanceOfBody elsewhere. Inlining into asInstanceOfOpt would fix that and shorten the code somewhat, but most of it is for primitiveToBoxedMap, and trust me that I could not find something like that available in the Scala standard library.

Scala convert List[Int] to a java.util.List[java.lang.Integer]

Is there a way in Scala to convert a List[Int] to java.util.List[java.lang.Integer]?
I'm interfacing with Java (Thrift).
JavaConversions supports List --> java.util.List, and implicits exist between Int --> java.lang.Integer, but from what I can tell I would still need an extra pass to manually do the conversion:
val y = List(1)
val z: java.util.List[Integer] = asList(y) map { (x: Int) => x : java.lang.Integer }
Apparently you need both conversions. However, you can group them in a single implicit conversion:
implicit def toIntegerList( lst: List[Int] ) =
seqAsJavaList( lst.map( i => i:java.lang.Integer ) )
Example:
scala> def sizeOf( lst: java.util.List[java.lang.Integer] ) = lst.size
scala> sizeOf( List(1,2,3) )
res5: Int = 3
Because the underlying representation of Int is Integer you can cast directly to java.util.List[java.lang.Integer]. It will save you an O(n) operation and some implicit stuff.
import collection.JavaConversions._
class A {
def l() = asList(List(1,2)).asInstanceOf[java.util.List[java.lang.Integer]]
}
Then you can use from Java like this:
A a = new A();
java.util.List<Integer> l = a.l();
Note that on 2.9.0 ,I get a deprecation warning on asList (use seqAsJavaList instead)
Did you try:
val javalist = collection.JavaConversions.asJavaList (y)
I'm not sure, whether you need a conversion Int=>Integer or Int=>int here. Can you try it out?
Update:
The times, they are a changing. Today you'll get a deprecated warning for that code. Use instead:
import scala.collection.JavaConverters._
val y = List (1)
> y: List[Int] = List(1)
val javalist = (y).asJava
> javalist: java.util.List[Int] = [1]
This doesn't have an implicit at the outmost layer, but I like this generic approach and have implemented it for a couple of types of collections (List, Map).
import java.util.{List => JList}
import scala.collection.JavaConverters._
def scalaList2JavaList[A, B](scalaList: List[A])
(implicit a2bConversion: A => B): JList[B] =
(scalaList map a2bConversion).asJava
Since an implicit conversion from Int to Integer is part of standard lib, usage in this case would just look like this:
scalaList2JavaList[Int, Integer](someScalaList)
In the other direction!
(since I have these available anyway as they were my original implementations...)
import java.util.{List => JList}
import scala.collection.JavaConversions._
def javaList2ScalaList[A, B](javaList: JList[A])
(implicit a2bConversion: A => B): List[B] =
javaList.toList map a2bConversion
Usage:
javaList2ScalaList[Integer, Int](someJavaList)
This can then be re-used for all lists so long as an implicit conversion of the contained type is in scope.
(And in case you're curious, here is my implementation for map...)
def javaMap2ScalaMap[A, B, C, D](javaMap: util.Map[A, B])(implicit a2cConversion: A => C, b2dConversion: B => D): Map[C, D] =
javaMap.toMap map { case (a, b) => (a2cConversion(a), b2dConversion(b)) }
Starting Scala 2.13, the standard library includes scala.jdk.CollectionConverters which provides Scala to Java implicit collection conversions.
Which we can combine with java.lang.Integer::valueOf to convert Scala's Int to Java's Integer:
import scala.jdk.CollectionConverters._
List(1, 2, 3).map(Integer.valueOf).asJava
// java.util.List[Integer] = [1, 2, 3]
I was trying to pass a Map[String, Double] to a Java method. But the problem was JavaConversions converts the Map to a java Map, but leaves the scala Double as is, instead of converting it to java.lang.Double. After a few hours of seaching I found [Alvaro Carrasco's answer])https://stackoverflow.com/a/40683561/1612432), it is as simple as doing:
val scalaMap = // Some Map[String, Double]
val javaMap = scalaMap.mapValues(Double.box)
After this, javaMap is a Map[String, java.lang.Double]. Then you can pass this to a java function that expects a Map<String, Double> and thanks to implicit conversions the Scala Map will be converted to java.util.Map
In your case would be the same, but with Int.box:
val y = List(1)
val javay = y.map(Int.box)

How to implement Map with default operation in Scala

class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] {
override def default(key: A) = List[B]()
}
I wan't to create map A -> List[B]. In my case it is Long -> List[String] but when I get key from map that doesn't have value I would like to create empty List instead of Exception being thrown. I tried different combinations but I don't know how to make code above pass the compiler.
Thanks in advance.
Why not to use withDefaultValue(value)?
scala> val m = Map[Int, List[String]]().withDefaultValue(List())
m: scala.collection.immutable.Map[Int,List[String]] = Map()
scala> m(123)
res1: List[String] = List()
Rather than using apply to access the map, you could always use get, which returns Option[V] and then getOrElse:
map.get(k) getOrElse Nil
One great feature of the scalaz functional-programming library is the unary operator ~, which means "or zero",as long as the value type has a "zero" defined (which List does, the zero being Nil of course). So the code then becomes:
~map.get(k)
This is doubly useful because the same syntax works where (for example) your values are Int, Double etc (anything for which there is a Zero typeclass).
There has been a great deal of debate on the scala mailing list about using Map.withDefault because of how this then behaves as regards the isDefinedAt method, among others. I tend to steer clear of it for this reason.
There's a method withDefaultValue on Map:
scala> val myMap = Map(1 -> List(10), 2 -> List(20, 200)).withDefaultValue(Nil)
myMap: scala.collection.immutable.Map[Int,List[Int]] = Map((1,List(10)), (2,List(20, 200)))
scala> myMap(2)
res0: List[Int] = List(20, 200)
scala> myMap(3)
res1: List[Int] = List()
Why do you want to manipulate a map when it has already a method for this?
val m = Map(1L->List("a","b"), 3L->List("x","y","z"))
println(m.getOrElse(1L, List("c"))) //--> List(a, b)
println(m.getOrElse(2L, List("y"))) //--> List(y)
withDefault can also be used.
/** The same map with a given default function.
* Note: `get`, `contains`, `iterator`, `keys`, etc are not affected
* by `withDefault`.
*
* Invoking transformer methods (e.g. `map`) will not preserve the default value.
*
* #param d the function mapping keys to values, used for non-present keys
* #return a wrapper of the map with a default value
*/
def withDefault[B1 >: B](d: A => B1): immutable.Map[A, B1]
Example:
scala> def intToString(i: Int) = s"Integer $i"
intToString: (i: Int)String
scala> val x = Map[Int, String]().withDefault(intToString)
x: scala.collection.immutable.Map[Int,String] = Map()
scala> x(1)
res5: String = Integer 1
scala> x(2)
res6: String = Integer 2
Hope this helps.