Как реализовать Map с операцией по умолчанию в Scala

class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] {
    override def default(key: A) = List[B]() 
  }

Я не хочу создавать карту A -> List[B]. В моем случае это Long -> List[String], но когда я получаю ключ от карты, которая не имеет значения, я хотел бы создать пустой List вместо выбрасываемого Exception. Я пробовал разные комбинации, но я не знаю, как заставить код выше пройти компилятор.

Заранее спасибо.


person Lukasz    schedule 29.04.2011    source источник
comment
В моем случае я обошелся, используя code val map = new HashMap[Long, List[String]]() { override def default(key: Long) = List[String]() }   -  person Lukasz    schedule 29.04.2011


Ответы (5)


Почему бы не использовать 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()
person Ilya Klyuchnikov    schedule 29.04.2011

Есть метод withDefaultValue на 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()
person kassens    schedule 29.04.2011
comment
А еще есть withDefault, который принимает функцию. - person Daniel C. Sobral; 29.04.2011

Почему вы хотите манипулировать картой, если у нее уже есть метод для этого?

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)
person Landei    schedule 29.04.2011
comment
Смотрите мой комментарий к @oxbow_lakes: это не то же самое, что задает ОП. Он управляет значениями по умолчанию при доступе к карте, а не при ее создании. - person Juh_; 04.01.2017

Также можно использовать withDefault.

/** 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]

Пример:

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

Надеюсь это поможет.

person tharindu_DG    schedule 05.04.2017

person    schedule
comment
Интересный ответ. Однако в этом шаге выполняется управление неопределенными элементами от создания карты до доступа к карте. В моем случае мне нужно передать карту методу, который уже имеет собственное поведение по умолчанию, которое я хочу переопределить (для теста). И я не могу изменить код, читающий карту. - person Juh_; 04.01.2017
comment
Это отличный ответ, потому что в вызывающем коде ясно указывается, откуда берется значение, если его нет на карте. Меньше магии. - person jeremyjjbrown; 02.10.2018
comment
и теперь можно записать как: map.getOrElse(k, Nil) - person Bob; 22.11.2019