通过Clojure中的键值过滤地图列表的简便方法

Art*_*tem 1 dictionary list clojure

我无法在Clojure中找到按键值过滤地图列表的内置功能.例如,我们有以下列表:

user=> (def animals (list {:name "Charlie" :weight 350 :specie :elephant}
                          {:name "Vasya" :weight 250 :specie :bear}
                          {:name "John" :weight 200 :specie :elephant}
                          {:name "Monk" :weight 200 :specie :monkey}))
#'user/animals
Run Code Online (Sandbox Code Playgroud)

我想选择所有:specie有价值的东西:elephant.我怎样才能做到这一点?我发现的最好方法是:

user=> (defn filter-data [data m]
         (let [k (keys m) v (vals m)]
           (filter #(= (map % k) v) data)))
#'user/filter-data

user=> (clojure.pprint/print-table (filter-data animals {:specie :elephant}))

|   :name | :weight |   :specie |
|---------+---------+-----------|
| Charlie |     350 | :elephant |
|    John |     200 | :elephant |
nil
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法呢?

Shl*_*omi 6

这可以通过过滤器轻松实现

(clojure.pprint/print-table 
  (filter #(= (:specie %) :elephant) animals))
Run Code Online (Sandbox Code Playgroud)

您始终可以将过滤器包装在函数中以获得不同的"语法",例如:

(defn cool-filter [[k v] l]
  (filter #(= (k %) v) l))

(clojure.pprint/print-table 
  (cool-filter [:specie :elephant] animals))
Run Code Online (Sandbox Code Playgroud)


Mic*_*ohl 6

虽然filter解决方案显然是最直接的,但我想添加一种替代方案,以防您需要查找多个物种:

(def grouped-animals (group-by :specie animals))
(:elephant grouped-animals)
; [{:name "Charlie", :weight 350, :specie :elephant} {:name "John", :weight 200, :specie :elephant}]
Run Code Online (Sandbox Code Playgroud)


小智 5

您还可以使用函数组合:

(filter (comp (partial = :elephant) :specie) animals)
Run Code Online (Sandbox Code Playgroud)

或者...

(filter (comp #{:elephant} :specie) animals)
Run Code Online (Sandbox Code Playgroud)