2016-04-27 40 views
3

我有包含HashMap的向量类似下面这样的格式:Clojure的 - 在包含HashMap的矢量返回最低HashMap的其中两个密钥匹配

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

我想筛选出最低:b值匹配:a值,所以如果两个值相同,例如{:a 1 :b 2}{:a 1 :b 6}它应该返回:{:a 1 :b 2}为2比6

所以对于矢量较低上面我想获得:

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

我已经尝试了一些东西,但我有点卡住,任何将不胜感激,谢谢。

+0

那你试试?你卡在哪里? – Shlomi

+0

你可以在ClojureDocs.org网站上找到comparitors的一个很好的解释(你想要的通用版本):http://clojuredocs.org/clojure.core/sorted-set-by –

+0

@Shlomi我试过这样的东西:'(apply min-key:b(filter#(=(:a%)3)list))''通过过滤所有的值,在列表中找到':b'的最小值,其中':a' = 3但我手动键入':a'值 –

回答

4

你的原始方向是正确的。你只错过了分组部:

(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}) 

首先,我们通过密钥:agroup地图的名单,并提取了它的价值。然后,我们检查每个组和关键:b

+0

感谢你,我认为这样做的表现会比通过列表两次更好,因为我正在使用我当前的解决方案 –

+0

您可以测试性能为自己与[critirium](https:// github。COM/hugoduncan /绕圈)。我相信这比你的解决方案更习惯一点,但它真的取决于你! – Shlomi

+0

有一个'min-key'功能?卫生署! –

-1

所以我思考了一下,我现在有一个答案(虽然不是一个很好的一个):

(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))) 
) 
) 

感谢大家的帮助,如果您有任何批评或更好的解决办法,请张贴它。

-1

随着依赖

[tupelo "0.1.68"] 

我们可以写出下面的代码。我在很多spy表现留下了这么

(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 []) 

运行,我们得到的代码:

--------------------------------- 
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}] 

回想起来,这可以简化更多,如果我们被保证的广告,每个输入地图就像{:一: b},因为我们可以将它简化为像[nm]这样的一系列2-D点,因为关键字:a:b将会减少。

-1

发现使用min-key最小值下面是一个使用group-by功能更好的答案:

(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 []) 

产生的结果

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}]