2012-05-16 5 views
10

Ich muss einen Schlüssel aus einer Karte mit einem Wert extrahieren. Gibt es eine Möglichkeit, dies zu tun, außer Reverse Lookup selbst zu implementieren?Reverse Lookup in einer Karte

+3

Was ich f 2 oder mehr Tasten haben den gleichen Wert? Brauchst du nur einen oder alle? – ivant

Antwort

3

(some #(if (= (val %) your-val) (key %)) your-map) 
6

Sie eine Karte wirklich leicht mit einer 2-Linien-Funktion rückgängig machen kann:

(defn reverse-map [m] 
    (into {} (map (fn [[a b]] [b a]) m))) 

(def a {:a 1 :b 2 :c 3}) 

(reverse-map a) 
=> {1 :a, 3 :c, 2 :b} 

((reverse-map a) 1) 
=> :a 
+1

Hinweis: Die Map '{: a 1: b 1}' wird für alle intensiven Zwecke undefiniert. – Jeremy

+0

@ Jeremy: Es ist nicht streng undefiniert, Sie erhalten zuverlässig eine Reverse-Lookup von entweder '{1: a}' oder '{1: b}' (welche Sie erhalten hängt von der internen Reihenfolge der hashmap). Aber ich stimme zu, dass Sie, wenn Sie doppelte Werte haben, dies wahrscheinlich etwas speziell behandeln möchten. – mikera

+0

Ja. Alles, was ich meinte, war, dass man sich nicht darauf verlassen sollte. Außerdem können kleine Maps, die PersistentArrayMaps sind, * vorhersagbares * (nicht unbedingt erwartetes) Verhalten haben, bis sie in eine PersistentHashMap umgewandelt werden. Aber darauf sollte man sich nicht verlassen. – Jeremy

0

ein noch einmal zu versuchen:

(defn reverse-map [m]                               
    (apply hash-map (mapcat reverse m))) 

(defn reverse-lookup [m k]                              
    (ffirst (filter (comp #{k} second) m))) 
25

Ich denke, dass map-invert das Recht ist Weg, dies zu tun.

From the docs:

;; Despite being in clojure.set, this has nothing to do with sets. 

user=> (map-invert {:a 1, :b 2}) 
{2 :b, 1 :a} 

;; If there are duplicate keys, one is chosen: 

user=> (map-invert {:a 1, :b 1}) 
{1 :b} 

;; I suspect it'd be unwise to depend on which key survives the clash. 
1

Wenn Sie ClojureScript verwenden oder benötigen Sie eine weitere Alternative :)

(zipmap (vals m) (keys m))

0

, wenn Sie die Schlüssel halten wollen, ist es besser, nur die Karte invertieren , aber sammeln Sie die alten Schlüssel in einem Set/in einer Liste usw.

(defn map-inverse [m] 
    (reduce (fn [m' [k v]] (update m' v clojure.set/union #{k})) {} m)) 

(defn map-inverse [m] 
    (reduce (fn [m' [k v]] (update m' v conj k)) {} m))