2016-04-27 2 views
3

Ich habe einen Vektor von Hashmaps mit einem Format ähnlich dem folgenden:Clojure - in einem Vektor von Hashmaps Rückkehr die niedrigste hashmap wo zwei Schlüssel passen

[{:a 1 :b 2} {:a 3 :b 4} {:a 1 :b 6} {:a 3 :b 9} {:a 5 :b 1} {:a 6 :b 1}] 

Ich möchte mich für den niedrigsten :b Wert herauszufiltern übereinstimmende :a Werte, also wenn zwei :a Werte gleich sind z {:a 1 :b 2}, {:a 1 :b 6} sollte es zurück: {:a 1 :b 2} als 2 niedriger als 6

So für den Vektor oben ich bekommen würde:

[{:a 1 :b 2} {:a 3 :b 4} {:a 5 :b 1} {:a 6 :b 1}] 

ich ein paar Dinge ausprobiert, aber ich bin ein bisschen stecken, jede Hilfe wäre dankbar, danke. So

+0

produziert Was haben Sie versucht, ? wo bleibst du stecken? – Shlomi

+0

Sie können eine gute Erklärung der Vergleicher (die generische Version von dem, was Sie wollen) auf der ClojureDocs.org Website finden: http://clojuredocs.org/clojure.core/sorted-set-by –

+0

@Shlomi Ich habe so etwas versucht : '(apply min-key: b (filter # (= (: a%) 3) Liste)' 'die den Minimalwert für': b' in der Liste findet, indem alle Werte herausgefiltert werden, wobei ': a' = 3 aber ich habe manuell den ': a'-Wert eingegeben –

Antwort

4

Ihre ursprüngliche Richtung war korrekt. Sie verfehlten nur die Gruppierung Teil:

(def test [{:a 1 :b 2} {:a 3 :b 4} {:a 1 :b 6} {:a 3 :b 9} {:a 5 :b 1} {:a 6 :b 1}]) 

(defn min-map [m] 
    (map (partial apply min-key :b) (vals (group-by :a m)))) 

(min-map test) 
=> ({:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1} {:a 6, :b 1}) 

Zuerst haben wir die Liste der Karten durch den Schlüssel :agroup, und die Werte davon extrahieren. Wir haben dann jede Gruppe untersuchen und den kleinsten Wert von Schlüssel :b

+0

danke dafür, ich nehme an, dass die Leistung, es auf diese Weise zu machen, besser wäre, als zweimal durch die Liste zu gehen, wie ich in meiner aktuellen Lösung tue –

+0

Sie können die Leistung testen für dich mit [kritirium] (https: // github.com/hugoduncan/Kriterium). Ich glaube, das ist etwas idiomatischer als deine Lösung, aber es liegt wirklich an dir! – Shlomi

+0

Es gibt eine 'min-key' Funktion ??? Do! –

-1

Ich dachte darüber nach ein bisschen und ich habe jetzt eine Antwort (wenn auch nicht sehr gut):

(defn contains [a vect] 
    (apply min-key :b(filter #(= (:a %) (:a a))vect)) 
) 

(defn starter [] 
    (let [tester [{:a 1 :b 2} {:a 3 :b 4} {:a 1 :b 6} {:a 3 :b 9} {:a 5 :b 1} {:a 6 :b 1}]] 
    (vec(distinct(map #(contains % tester)tester))) 
) 
) 

Vielen Dank für everyones helfen, wenn Sie irgendwelche Kritik oder eine bessere Lösung haben, bitte schreiben es.

-1

Mit der Abhängigkeit

[tupelo "0.1.68"] 

können wir den folgenden Code schreiben. Ich ließ in vielen spy Ausdrücke so

(ns clj.core 
    (:use tupelo.core) 
    (:require [clojure.core    :as clj] 
      [schema.core    :as s] 
      [tupelo.types    :as tt] 
      [tupelo.schema    :as ts] 
)) 

; Prismatic Schema type definitions 
(s/set-fn-validation! true) ; #todo add to Schema docs 

(def data [ {:a 1 :b 2} {:a 3 :b 4} {:a 1 :b 6} {:a 3 :b 9} {:a 5 :b 1} {:a 6 :b 1} ]) 

(defn accum-smallest-b-entries 
    [cum-map-a2b 
     ; A map where both keys and vals are simple 1-entry maps 
     ; like: {:a 1} -> {:b 2} 
     ;   {:a 2} -> {:b 9} 
    new-a-b-map 
     ; next entry, like {:a 1 :b 2} 
    ] 
    (newline) 
    (println "---------------------------------") 
    (let [new-a-map (select-keys new-a-b-map [:a]) ; like {:a 1} 
     _ (spyx new-a-map) 
     new-b-map (select-keys new-a-b-map [:b]) ; like {:b 2} 
     _ (spyx new-b-map) 
     curr-b-map (get cum-map-a2b new-a-map) 
     _ (spyx curr-b-map) 
     next-b-map (if (or (nil? curr-b-map) 
          (< (grab :b new-b-map) (grab :b curr-b-map))) 
         new-b-map 
         curr-b-map) 
     _ (spyx next-b-map) 
    ] 
    (spyx (assoc cum-map-a2b new-a-map next-b-map)))) 

(def a2b-map (reduce accum-smallest-b-entries {} data)) 
(spyx a2b-map) 

(defn combine-keyvals-from-a2b-map 
    [cum-result 
     ; final result like: [ {:a 1 :b 2} 
     ;      {:a 2 :b 9} ] 
    a2b-entry 
     ; next entry from a2b-map like [ {:a 5} {:b 1} ] 
    ] 
    (newline) 
    (println "combine-keyvals-from-a2b-map") 
    (println "---------------------------------") 
    (spyx cum-result) 
    (spyx a2b-entry) 
    (let [combined-ab-map (glue (first a2b-entry) (second a2b-entry)) 
     _ (spyx combined-ab-map) 
     new-result  (append cum-result combined-ab-map) 
     _ (spyx new-result) 
     ] 
    new-result)) 

(def a-and-b-map (reduce combine-keyvals-from-a2b-map [] a2b-map)) 
(spyx a-and-b-map) 

(defn -main []) 

den Code Laufen erhalten wir:

--------------------------------- 
new-a-map => {:a 1} 
new-b-map => {:b 2} 
curr-b-map => nil 
next-b-map => {:b 2} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}} 

--------------------------------- 
new-a-map => {:a 3} 
new-b-map => {:b 4} 
curr-b-map => nil 
next-b-map => {:b 4} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}, {:a 3} {:b 4}} 

--------------------------------- 
new-a-map => {:a 1} 
new-b-map => {:b 6} 
curr-b-map => {:b 2} 
next-b-map => {:b 2} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}, {:a 3} {:b 4}} 

--------------------------------- 
new-a-map => {:a 3} 
new-b-map => {:b 9} 
curr-b-map => {:b 4} 
next-b-map => {:b 4} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}, {:a 3} {:b 4}} 

--------------------------------- 
new-a-map => {:a 5} 
new-b-map => {:b 1} 
curr-b-map => nil 
next-b-map => {:b 1} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}, {:a 3} {:b 4}, {:a 5} {:b 1}} 

--------------------------------- 
new-a-map => {:a 6} 
new-b-map => {:b 1} 
curr-b-map => nil 
next-b-map => {:b 1} 
(assoc cum-map-a2b new-a-map next-b-map) => {{:a 1} {:b 2}, {:a 3} {:b 4}, {:a 5} {:b 1}, {:a 6} {:b 1}} 
a2b-map => {{:a 1} {:b 2}, {:a 3} {:b 4}, {:a 5} {:b 1}, {:a 6} {:b 1}} 

combine-keyvals-from-a2b-map 
--------------------------------- 
cum-result => [] 
a2b-entry => [{:a 1} {:b 2}] 
combined-ab-map => {:a 1, :b 2} 
new-result => [{:a 1, :b 2}] 

combine-keyvals-from-a2b-map 
--------------------------------- 
cum-result => [{:a 1, :b 2}] 
a2b-entry => [{:a 3} {:b 4}] 
combined-ab-map => {:a 3, :b 4} 
new-result => [{:a 1, :b 2} {:a 3, :b 4}] 

combine-keyvals-from-a2b-map 
--------------------------------- 
cum-result => [{:a 1, :b 2} {:a 3, :b 4}] 
a2b-entry => [{:a 5} {:b 1}] 
combined-ab-map => {:a 5, :b 1} 
new-result => [{:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1}] 

combine-keyvals-from-a2b-map 
--------------------------------- 
cum-result => [{:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1}] 
a2b-entry => [{:a 6} {:b 1}] 
combined-ab-map => {:a 6, :b 1} 
new-result => [{:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1} {:a 6, :b 1}] 
a-and-b-map => [{:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1} {:a 6, :b 1}] 

Im Nachhinein könnte es vereinfacht mehr, wenn wir, dass jede Eingangskarte guarenteed wurden, war wie {: a: b}, da wir es zu einer Reihe von 2-d-Punkten wie [nm] vereinfachen könnten, da die Schlüsselwörter :a und :b reduktiv wären.

-1

Hier mit min-key finden, ist eine bessere Antwort mit der group-by Funktion:

(ns clj.core 
    (:use tupelo.core) 
    (:require [clojure.core    :as clj] 
      [schema.core    :as s] 
      [tupelo.types    :as tt] 
      [tupelo.schema    :as ts] 
)) 

; Prismatic Schema type definitions 
(s/set-fn-validation! true) ; #todo add to Schema docs 

(def data [ {:a 1 :b 2} {:a 3 :b 4} {:a 1 :b 6} {:a 3 :b 9} {:a 5 :b 1} {:a 6 :b 1} ]) 

(def data-by-a (group-by :a data)) 
    ; like { 1 [{:a 1, :b 2} {:a 1, :b 6}], 
    ;  3 [{:a 3, :b 4} {:a 3, :b 9}], 
    ;  5 [{:a 5, :b 1}], 
    ;  6 [{:a 6, :b 1}] } 
(spyx data-by-a) 

(defn smallest-map-by-b 
    [curr-result ; like {:a 1, :b 2} 
    next-value] ; like {:a 1, :b 6} 
    (if (< (grab :b curr-result) 
      (grab :b next-value)) 
    curr-result 
    next-value)) 

(defn find-min-b 
    "Return the map with the smallest b value" 
    [ab-maps] ; like [ {:a 1, :b 2} {:a 1, :b 6} ] 
    (reduce smallest-map-by-b 
      (first ab-maps) ; choose 1st as init guess at result 
      ab-maps)) 

(def result 
    (glue 
    (for [entry data-by-a] ; entry is MapEntry like: [ 1 [{:a 1, :b 2} {:a 1, :b 6}] ] 
     (spyx (find-min-b (val entry))) 
    ))) 
(spyx result) 

(defn -main []) 

, die das Ergebnis

data-by-a => {1 [{:a 1, :b 2} {:a 1, :b 6}], 3 [{:a 3, :b 4} {:a 3, :b 9}], 5 [{:a 5, :b 1}], 6 [{:a 6, :b 1}]} 
(find-min-b (val entry)) => {:a 1, :b 2} 
(find-min-b (val entry)) => {:a 3, :b 4} 
(find-min-b (val entry)) => {:a 5, :b 1} 
(find-min-b (val entry)) => {:a 6, :b 1} 
result => [{:a 1, :b 2} {:a 3, :b 4} {:a 5, :b 1} {:a 6, :b 1}] 
Verwandte Themen