2017-10-30 2 views
0

Ich habe eine verschachtelte Clojure Karte:Clojure: sorten durch verschachtelten Karte benutzerdefinierten Komparator

{ 
    :1 { 
    :priority "Medicore" 
    :somekey "SomeValue" 
    }, 
    :2 { 
    :priority "Enormous" 
    :somekey "SomeValue" 
    }, 
    :3 { 
    :priority "Weeny" 
    :somekey "SomeValue" 
    } 
} 

Mein Ziel ist es, den Wert von somekey aus der Karte mit der „höchsten“ Priorität zu erhalten. Die äußere Karte kann 0-n Elemente mit einer der drei Prioritäten enthalten. Wenn es mehrere Einträge mit der höchsten verfügbaren Priorität gibt, ist es in Ordnung, irgendeinen zu nehmen.

Nachdem ich einige andere SO Fragen untersucht habe, dachte ich, ein guter Weg, um dieses Problem zu lösen, wäre die Verwendung der sort-by Funktion. Aber da meine priority nicht natürlich sortiert ist, müsste ich einen benutzerdefinierten Komparator bereitstellen.

Ist das möglich? Ist meine Herangehensweise auch die richtige für mein Ziel?

Antwort

1

Um sort-by zu verwenden, müssen Sie eine Bestellung oder Ihre Prioritätswerte angeben. Sie können einen benutzerdefinierten Komparator implementieren, um Ihre Maps zu vergleichen, oder einen Keyfn für sort-by definieren, der den für die Sortierung verwendeten Schlüssel berechnet. Die Lösung mit Keyfn ist unten. Mit nur dem Keyfn-Rückgabewert ist ein vergleichbarer Wert, der Ihren Anforderungen entspricht, wesentlich einfacher als die Implementierung eines Vergleichers. Vielleicht möchten Sie einen Blick auf Comparators Guide werfen.

Wir beginnen, die eine Funktion eine Zeichenfolge Priorität in seine numerische Darstellung zu konvertieren:

(let [priorities {"Medicore" 0 
        "Enormous" 1 
        "Weeny" 2}] 
    (defn priority->num [p] 
    (if-let [num (priorities p)] 
     num 
     (throw (IllegalArgumentException. (str "Unknown priority: " p)))))) 

(priority->num "Enormous") 
;; => 1 

Jetzt müssen wir für jede Karte max Priorität berechnen:

(defn max-priority-num [m] 
    (->> m 
     (vals) 
     (map (comp priority->num :priority)) 
     (apply max))) 

(max-priority-num {:1 {:priority "Medicore" :somekey "SomeValue"} 
        :2 {:priority "Enormous" :somekey "SomeValue"} 
        :3 {:priority "Weeny" :somekey "SomeValue"}}) 
;; => 2 

Jetzt können wir endlich sort-by verwenden :

(def m1 {:1 {:priority "Medicore" :somekey "SomeValue"} 
     :2 {:priority "Medicore" :somekey "SomeValue"} 
     :3 {:priority "Weeny" :somekey "SomeValue"}}) 

(def m2 {:1 {:priority "Medicore" :somekey "SomeValue"} 
     :2 {:priority "Enormous" :somekey "SomeValue"} 
     :3 {:priority "Weeny" :somekey "SomeValue"}}) 

(def m3 {:1 {:priority "Medicore" :somekey "SomeValue"} 
     :2 {:priority "Medicore" :somekey "SomeValue"} 
     :3 {:priority "Medicore" :somekey "SomeValue"}}) 

(sort-by max-priority-num [m1 m2 m3]) 
;; => 
({:1 {:priority "Medicore", :somekey "SomeValue"}, 
    :2 {:priority "Medicore", :somekey "SomeValue"}, 
    :3 {:priority "Medicore", :somekey "SomeValue"}} 
{:1 {:priority "Medicore", :somekey "SomeValue"}, 
    :2 {:priority "Medicore", :somekey "SomeValue"}, 
    :3 {:priority "Weeny", :somekey "SomeValue"}} 
{:1 {:priority "Medicore", :somekey "SomeValue"}, 
    :2 {:priority "Enormous", :somekey "SomeValue"}, 
    :3 {:priority "Weeny", :somekey "SomeValue"}}) 
+0

Dies ist viel einfacher mit 'max-key' als' sort-by'. – amalloy

+0

Right @amalloy, ich habe übersehen OP wollte das maximale Element, nicht alle Elemente sortiert bekommen! Anstatt also '(sort-by max-priority-num [m2 m2 m3])', '(max-key max-priority-num m1 m2 m3)' oder '(max-key max-priority-num maps) zu benennen) 'wäre besser. –

Verwandte Themen