2011-04-29 7 views
33
class DefaultListMap[A, B <: List[B]] extends HashMap[A, B] { 
    override def default(key: A) = List[B]() 
    } 

Quiero crear el mapa A -> List[B]. En mi caso es Long -> List[String] pero cuando obtengo la clave del mapa que no tiene valor, me gustaría crear List vacío en lugar de Exception que se está lanzando. Probé diferentes combinaciones, pero no sé cómo hacer que el código pase el compilador.Cómo implementar el mapa con la operación predeterminada en Scala

Gracias de antemano.

+0

me dieron vueltas en mi caso, mediante el uso de 'código mapa val = new HashMap [Larga, Lista [cadena]]() { anulación por defecto def (clave: Long) = Lista [String]() } ' – Lukasz

Respuesta

78

Por qué no usar withDefaultValue (valor)?

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

¿Por qué quiere manipular un mapa cuando ya tiene un método para esto?

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) 
+0

Vea mi comentario a @oxbow_lakes: esto no es lo mismo que lo que pide el OP. Administra el acceso predeterminado al mapa, en lugar de la creación del mapa. –

18

En lugar de utilizar apply para acceder al mapa, siempre se puede utilizar get, que devuelve Option[V] y luego getOrElse:

map.get(k) getOrElse Nil 

Una gran característica de la scalazbiblioteca de programación funcional es el operador unario ~, que significa "o cero", siempre que el tipo de valor tenga un "cero" definido (que List hace, siendo el cero Nil por supuesto). Así que el código se convierte entonces en:

~map.get(k) 

Esto es doblemente útil, porque la misma sintaxis funciona en (por ejemplo) son sus valores Int, Double etc (cualquier cosa para la que no es una clase de tipos Zero).


Ha habido un gran debate sobre la lista de correo sobre el uso de Scala Map.withDefault debido a cómo esta se comporta entonces como que respecta al método isDefinedAt, entre otros. Por esta razón, tiendo a evitarlo.

+0

Interesante respuesta. Sin embargo, este movimiento donde se hace la gestión de elementos indefinidos desde la creación del mapa hasta el acceso al mapa. En mi caso, necesito pasar un Mapa a un método que ya tiene su propio comportamiento predeterminado, que quiero anular (para una prueba).Y no puedo cambiar el código que lee el mapa. –

9

Hay un método withDefaultValue en 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() 
+8

Y también hay un 'withDefault', que toma una función. –

2

withDefault también se puede utilizar.

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

Ejemplo:

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 

Espero que esto ayude.

Cuestiones relacionadas