2012-02-15 18 views
6

Con respecto a los mapas en Scala, si ms - (k, 1, m) devuelve el mapa que contiene todas las asignaciones de ms excepto para cualquier asignación con las claves dadas, x, 1 y m.Mapa con solo ciertas teclas

Entonces, ¿qué enunciado devolverá un mapa de todas las asignaciones de ms con solo las teclas dadas, x, 1 y m. es decir, estoy buscando el subconjunto de ms donde solo k, 1 ym son claves.

Esto funciona, pero es terrible:

scala> val originalMap = Map("age" -> "20", "name" -> "jack", "hobby" -> "jumping") 
ms: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(age -> 20, name -> jack, hobby -> jumping) 

scala> val interestingKeys = List("name", "hobby") 
interesting: List[java.lang.String] = List(name, hobby) 

scala> val notInterestingMap = originalMap -- interestingKeys 
notInterestingMap: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(age -> 20) 

scala> val interestingMap = originalMap -- notInterestingMap.keySet 
interestingMap: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(name -> jack, hobby -> jumping) 

Respuesta

7

Debido filterKeys filtros basados ​​en un predicado arbitraria, tiene que considerar cada clave en el mapa. Esto podría estar bien o no, dependiendo de qué tan grande sea el mapa, etc., pero definitivamente no es necesario para la operación que describes. Me gustaría usar algo como lo siguiente:

interestingKeys.flatMap(k => originalMap.get(k).map((k, _))).toMap 

Ésta será O(n) o O(n log m) dependiendo de la implementación mapa (donde n es el tamaño de interestingKeys y m es el tamaño del mapa), en lugar de o O(mn) .

Si realmente quiere que su operador de ~, puede utilizar los pimp-my-library pattern:

class RichMap[A, B](m: Map[A, B]) { 
    def ~(ks: A*) = ks.flatMap(k => m.get(k).map((k, _))).toMap 
} 

implicit def enrichMap[A, B](m: Map[A, B]) = new RichMap(m) 

ahora originalMap ~ ("name", "hobby") vuelve Map(name -> jack, hobby -> jumping), como era de esperar.

+0

Para aquellos que usan persistencia AKKA vale la pena mencionar que la salida 'filterKeys' es _not_ serializable, me enfrenté a eso y me tomó un tiempo hasta que me di cuenta. Ver https://issues.scala-lang.org/browse/SI-6654 –

7

filterKeys pueden ayudar:

scala> originalMap.filterKeys(interestingKeys.contains) 
res0: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(name -> jack, hobby -> jumping) 
+2

posible mejora con interestingKeys.toSet' en lugar de 'interestingKeys contains', ya que es probable que la comprobación de membresía en un conjunto sea más eficiente. No con una lista de dos elementos sin embargo. –

+1

y no si pasa una lista de elementos distinc. Claramente depende del contexto. – Nicolas

+2

¿Por qué los distintos elementos cambiarían eso? Las pruebas de membresía aún serían O (n) en lugar de O (1) u O (log n) para una implementación de conjunto típico. –

1

creo que el código original no es tan malo, y que se puede transformar fácilmente en una sola línea que operan en el juego de llaves:

val interestingMap = originalMap -- (originalMap.keySet -- interestingKeys) 

Me parece bastante legible.

Cuestiones relacionadas