51
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.

1
  • 1
    I got around in my case by using code val map = new HashMap[Long, List[String]]() { override def default(key: Long) = List[String]() } Commented Apr 29, 2011 at 9:57

5 Answers 5

124

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()
Sign up to request clarification or add additional context in comments.

1 Comment

please be aware of the scala SDK issue with default values with Maps. m(123) will work, but m.get(123) will give you None.
26

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.

3 Comments

Interesting answer. However, this move where is done the management of undefined items from the map creation to the map access. In my case, I need to pass a Map to a method which already has its own default behavior, that I want to override (for a test). And I cannot change the code that read the map.
This is a great answer because it make clear in the calling code where a value is coming from if it's not in the map. Less magic.
and now can be written as: map.getOrElse(k, Nil)
11

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()

2 Comments

And there's also a withDefault, which takes a function.
please be aware of the scala SDK issue with default values with Maps. myMap(3) will work, but myMap.get(3) will give you None.
4

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)

1 Comment

See my comment to @oxbow_lakes: this is not the same as what is asked by the OP. It manages default at map access, instead of at the map creation.
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.