2012-02-15 11 views
6

Per quanto riguarda le mappe in Scala, se ms - (k, 1, m) restituisce la mappa contenente tutte le mappature di ms eccetto per qualsiasi mappatura con le chiavi specificate, x, 1 e m.Mappa con solo determinati tasti

Quindi, quale istruzione restituirà una mappa di tutte le mappature di ms con solo le chiavi specificate, x, 1 e m. io sto cercando il sottoinsieme di ms dove solo k, 1 ed m sono chiavi.

questo funziona, ma è terribile:

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) 

risposta

7

perché filterKeys filtri basati su un predicato arbitraria, deve considerare ogni chiave nella mappa. Questo potrebbe andar bene o no, a seconda di quanto è grande la mappa, ecc., Ma sicuramente non è necessario per l'operazione che descrivi. Mi piacerebbe usare qualcosa di simile a quanto segue:

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

Questo sarà O(n) o O(n log m) seconda dell'implementazione mappa (dove n è la dimensione del interestingKeys e m è la dimensione della mappa), invece di o O(mn) .

Se si vuole veramente il proprio operatore ~, è possibile utilizzare i 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) 

ora originalMap ~ ("name", "hobby") rendimenti Map(name -> jack, hobby -> jumping), come ci si aspetterebbe.

+0

Per coloro che usano la persistenza dell'AKKA vale la pena menzionare che l'output di 'filterKeys' è _not_ serializzabile, l'ho affrontato e ci ho messo un po 'di tempo prima che me ne rendessi conto. Vedi https://issues.scala-lang.org/browse/SI-6654 –

7

filterKeys può aiutare:

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

possibile miglioramento con interestingKeys.toSet' invece di 'interestingKeys contains', poiché è probabile che il controllo dell'appartenenza a un insieme sia più efficiente. Tuttavia, non con una lista di due elementi. –

+1

e non se si passa una lista di elementi distinti. Dipende chiaramente dal contesto. – Nicolas

+2

Perché gli elementi distinti lo cambierebbero? Il test di appartenenza sarebbe ancora O (n) anziché O (1) o O (log n) per un'implementazione tipica dell'insieme. –

1

penso che il codice originale non è così male, e può essere facilmente trasformato in una battuta che operano su set di chiavi:

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

Trovo che questo sia abbastanza leggibile.

Problemi correlati