如何在 Clojure 中正确“过滤”地图?

std*_*out 0 dictionary clojure

我已经使用 Clojure 玩了一段时间,我陷入了一些我认为对许多人来说非常微不足道的事情......但不是我。我有以下代码;

;; Define a Record structure
(defrecord Person [first-name last-name age occupation])

(def john (->Person "John" "Frusciante" 50 "Guitarist"))

;; People map
(def people {"1" john
             "2" (->Person "Pablo" "Neruda" 90 "Poet")
             "3" (->Person "Stefan" "Zweig" 120 "Author")
             }
) 

(defn get-120-year-old-guy
  [peeps]
  (filter #(= (:age %) 120) peeps)
)

(println "who's 120?: " (get-120-year-old-guy people))
Run Code Online (Sandbox Code Playgroud)

此调用返回一个空列表。我知道我检索值的方式有问题,但看不到那到底是什么。

Car*_*ate 8

您可以通过临时更改函数来了解正在发生的事情:

(defn get-120-year-old-guy
  [peeps]
  (filter (fn [m] (println (type m) m)) peeps))
Run Code Online (Sandbox Code Playgroud)

印刷:

(clojure.lang.MapEntry [1 #user.Person{:first-name John, :last-name Frusciante, :age 50, :occupation Guitarist}]
clojure.lang.MapEntry [2 #user.Person{:first-name Pablo, :last-name Neruda, :age 90, :occupation Poet}]
clojure.lang.MapEntry [3 #user.Person{:first-name Stefan, :last-name Zweig, :age 120, :occupation Author}]
)
Run Code Online (Sandbox Code Playgroud)

请注意每个条目是一个MapEntry. 在您的尝试中,您申请:age的是整体MapEntry(返回nil),而不仅仅是个人。

我认为使用完整的匿名函数进行解构将是最简单的方法:

(defn get-120-year-old-guy
  [peeps]
  (filter (fn [[_ person]] (= (:age person) 120)) peeps))
Run Code Online (Sandbox Code Playgroud)

输出:

who's 120?:  ([3 #user.Person{:first-name Stefan, :last-name Zweig, :age 120, :occupation Author}])
Run Code Online (Sandbox Code Playgroud)

@leetwinski 指出了一个更惯用的解决方案,它完全取消了显式函数:

(filter (comp #{120} :age val) people)
Run Code Online (Sandbox Code Playgroud)

分解:

(defn get-120-year-old-guy [peeps]
  (filter (comp  ; And (comp)ose all three checks together
             #{120}  ; Then test if it's in the set of #{120}
             :age  ; Then get the age
             val)  ; Get the value from the MapEntry
           peeps))
Run Code Online (Sandbox Code Playgroud)

  • 或者只是 `(filter (comp #{120} :age val) people)` (2认同)