Clojure - 在hashmaps向量中返回两个键匹配的最低hashmap

时间:2016-04-27 23:58:25

标签: clojure 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值相同,例如{: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}]

我尝试了一些事情,但我有点卡住了,感谢任何帮助,谢谢。

4 个答案:

答案 0 :(得分: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})

首先我们group按键:a列出地图列表,然后提取它的值。然后,我们检查每个组,并使用:b

min-key找到最小值

答案 1 :(得分:-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)))
)
)

感谢大家的帮助,如果您有任何批评或更好的解决方案,请发布。

答案 2 :(得分:-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}]

事后看来,如果我们保证每个输入地图都像{:a:b}那样可以简化它,因为我们可以将它简化为一系列2-d点,如[nm],因为关键字{ {1}}和:a将是还原剂。

答案 3 :(得分:-1)

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