繁体   English   中英

如何通过Clojure中的多个键过滤地图矢量

[英]How to filter vector of maps by multiple keys in Clojure

假设我们有一个这样的数据结构:

(def data
     (atom [{:id 1 :first-name "John1" :last-name "Dow1" :age "14"}
            {:id 2 :first-name "John2" :last-name "Dow2" :age "54"}
            {:id 3 :first-name "John3" :last-name "Dow3" :age "34"}
            {:id 4 :first-name "John4" :last-name "Dow4" :age "12"}
            {:id 5 :first-name "John5" :last-name "Dow5" :age "24"}]))

我已经学会了如何一键过滤,例如:

(defn my-filter
  [str-input]
  (filter #(re-find (->> (str str-input)
                         (lower-case)
                         (re-pattern))
                         (lower-case (:first-name %)))
            @data))

> (my-filter "John1")
> ({:last-name "Dow1", :age "14", :first-name "John1", :id 1})

但是现在我对如何通过:first-name:last-name:age简单方法过滤数据感到有些困惑?

更新:抱歉,在解释问题时不够清楚……实际上,我希望所有键:first-name:last-name:age都能参与过滤功能,这样,如果str-input不匹配:first-name的 val,检查它是否匹配:last-name的 val 等等。

更新 2 :在尝试some-fnevery-predtransducers ,我没有得到我需要的东西,例如过滤谓词中的正则表达式,我想这是现​​在缺乏知识。 所以,我最终得到了这个工作正常的函数,但代码很丑陋且重复。 我怎样才能摆脱代码重复?

(defn my-filter [str-input]
  (let [firstname (filter #(re-find (->> (str str-input)
                                         (upper-case)
                                         (re-pattern))
                                    (upper-case (:first-name %)))
                     @data)
        lastname (filter #(re-find (->> (str str-input)
                                        (upper-case)
                                        (re-pattern))
                                   (upper-case (:last-name %)))
                    @data)
        age (filter #(re-find (->> (str str-input)
                                   (upper-case)
                                   (re-pattern))
                              (upper-case (:age %)))
               @data)]
    (if-not (empty? firstname)
      firstname
      (if-not (empty? lastname)
        lastname
        (if-not (empty? age)
          age)))))

我认为这对你有用。 使用 Clojure 中的 :first-name 是一个函数,可用于在哈希图中查找其对应的值。

(defn find-all 
  [field value data] 
  (filter #(= value (field %)) data))

这将返回向量中匹配哈希图的列表。

user=> (find-all :first-name "John1" @data)
({:id 1, :first-name "John1", :last-name "Dow1", :age "14"})

如果您没有强烈的理由不这样做,我建议您将年龄存储为整数而不是字符串。

有关关键字的更多信息:

(:键映射)

  • 当您的地图为零时有效
user=> (:key-word nil) nil
  • 可以与地图或过滤器一起使用
user=> (map :last-name @data) ("Dow1" "Dow2" "Dow3" "Dow4" "Dow5")
  • :key 不能为零
user=> (nil (first @data)) CompilerException java.lang.IllegalArgumentException: Can't call nil, form: (nil (first (clojure.core/deref data))),

编译:(/private/var/folders/nr/g50ld9t91c555dzv91n43bg40000gn/T/form-init5403593628725666667.clj:1:1)

(地图:键)

  • 当 :key 为零时更好
user=> ((first @data) nil) nil

这也可以在函数组合的帮助下实现,例如您可以使用every-pred函数,它创建一个函数,检查所有 pred 的参数是否为真,并使用它来过滤数据。 例如,如果您想查找所有奇数:id值的项目,其:last-name"Dow1", "Dow2","Dow3"并且:age\\3开头:

user> (def data
  [{:id 1 :first-name "John1" :last-name "Dow1" :age "14"}
   {:id 2 :first-name "John2" :last-name "Dow2" :age "54"}
   {:id 3 :first-name "John3" :last-name "Dow3" :age "34"}
   {:id 4 :first-name "John4" :last-name "Dow4" :age "12"}
   {:id 5 :first-name "John5" :last-name "Dow5" :age "24"}])

user> (filter (every-pred (comp odd? :id)
                          (comp #{"Dow1" "Dow2" "Dow3"} :last-name)
                          (comp #{\3} first :age))
              data)

;;=> ({:id 3, :first-name "John3", :last-name "Dow3", :age "34"})

另一种方法是使用传感器

user> (sequence (comp (filter (comp odd? :id))
                      (filter (comp #{"Dow1" "Dow2" "Dow3"} :last-name)))
                data)

请注意,实际过滤对于每个项目只会发生一次,因此它不会创建任何中间集合。

更新

根据您的更新,当任何谓词为真时,您需要保留该值,因此您可以使用some函数而不是every-pred

user> (filter #(some (fn [pred] (pred %))
                     [(comp odd? :id)
                      (comp #{"Dow1" "Dow2" "Dow4"} :last-name)
                      (comp (partial = \3) first :age)])
              data)
;;=> ({:id 1, :first-name "John1", :last-name "Dow1", :age "14"} {:id 2, :first-name "John2", :last-name "Dow2", :age "54"} {:id 3, :first-name "John3", :last-name "Dow3", :age "34"} {:id 4, :first-name "John4", :last-name "Dow4", :age "12"} {:id 5, :first-name "John5", :last-name "Dow5", :age "24"})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM