Filter 按地图提供的多个属性筛选集合

Filter 按地图提供的多个属性筛选集合,filter,clojure,Filter,Clojure,我有一个要筛选的集合。过滤器使用一个映射完成,其中键是集合项中的属性,值是集合项应匹配的值。例如: (let [filters {:name "test" :type "new"} collection [{:name "testable" :type "old"} {:name "shoudwork" :type "new"} {:name "testable" :type "

我有一个要筛选的集合。过滤器使用一个映射完成,其中键是集合项中的属性,值是集合项应匹配的值。例如:

(let [filters {:name "test"
               :type "new"}
      collection [{:name "testable"  :type "old"}
                  {:name "shoudwork" :type "new"}
                  {:name "testable"  :type "new"}]])
现在,我已经构建了过滤器函数,只接受单个属性和值。我想扩展它,使它实际上能够接受一个过滤器
hashmap

这就是我当前的筛选器的外观:

(filter #(re-find (re-pattern "test") (string/lower-case (% :name))) collection)

换句话说,我希望
过滤器
不采用
“test
”硬编码,但它应该是
过滤器
let绑定的值,并且
(:name)
不硬编码为
:name
,但是要成为过滤器中的键让绑定。

创建一个函数,返回单个[键期望值]的过滤函数:

(defn regex-value [[k expected-rex]]
  (fn [c] (re-find (re-pattern expected-rex) 
                   (clojure.string/lower-case (get c k)))))
创建将创建复合过滤条件的函数:

(defn build-filter [filters]
  (apply every-pred (map regex-value filters)))
使用它:

(let [filters {:name "test"
               :type "new"}
      collection [{:name "testable"  :type "old"}
                  {:name "shoudwork" :type "new"}
                  {:name "testable"  :type "new"}]]
  (filter (build-filter filters) collection))

您也可以使用传感器:

;; first you create a filtering step factory for transduction:
(defn make-filter [[k v]]
  (filter #(re-find (re-pattern v)
                    (clojure.string/lower-case (k %)))))

;; and then transform the collection:
(let [filters {:name "test"
               :type "new"}
      collection [{:name "testable"  :type "old"}
                  {:name "shoudwork" :type "new"}
                  {:name "testable"  :type "new"}]]
  (sequence (reduce comp (map make-filter filters)) collection))

我非常喜欢这个,因为它使用
每个pred
。我尝试将其纳入我自己的解决方案中,但失败了。