我编写以下函数将s2合并到s1中,并且任何"id"值与s1中的任何元素相同的元素都不会合并.
(defn into-unique-id
[s1, [x2 & xs2]]
(if x2 (if (empty (filter (fn [x] (= (get x "id") (get x2 "id"))) s1)) (into-unique-id (conj s1 x2) xs2) (into-unique-id s1 xs2))
s1))
Run Code Online (Sandbox Code Playgroud)
我在REPL中尝试了以下内容.
gridizela.core=> (def s1 [{"id" "1"} {"id" "2"}])
#'gridizela.core/s1
gridizela.core=> (into-unique-id s1 [{"id" "1"}])
[{"id" "1"} {"id" "2"} {"id" "1"}]
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,结果并不像我预期的那样,不应该添加最后一个元素.
任何帮助,将不胜感激.
为了解决你的问题,我不得不做一些重构,我将包括每个版本的代码,以显示获得理想结果所需的步骤.
;; original
(defn into-unique-id
[s1, [x2 & xs2]]
(if x2 (if (empty (filter (fn [x] (= (get x "id") (get x2 "id"))) s1)) (into-unique-id (conj s1 x2) xs2) (into-unique-id s1 xs2))
s1))
Run Code Online (Sandbox Code Playgroud)
原始代码异常布局,使我难以阅读,难以理解.所以我的第一步是应用正常的缩进.
;; indentation
(defn into-unique-id-2
[s1, [x2 & xs2]]
(if x2
(if (empty (filter (fn [x] (= (get x "id")
(get x2 "id")))
s1))
(into-unique-id (conj s1 x2) xs2)
(into-unique-id s1 xs2))
s1))
Run Code Online (Sandbox Code Playgroud)
当我到达这一点时,我仍然没有完全得到代码,但我看到一些小的变化,这将使它更容易阅读.cond几乎总是你想要的东西而不是嵌套条件.我使用,,空格来区分结果子句和条件子句cond.
;; simplification
(defn into-unique-id-3
[s1, [x2 & xs2]]
(cond (not x2)
,, s1
(empty (filter (fn [x] (= (get x "id")
(get x2 "id")))
s1))
,, (into-unique-id (conj s1 x2) xs2)
:else
(into-unique-id s1 xs2)))
Run Code Online (Sandbox Code Playgroud)
此时我终于看到了错误:(empty x)将返回任何非零输入的truthy,即使是空集合.我们在这里真正想要的是欺骗性地命名(但非常不同)的empty?功能.
;; fix -- empty is always truthy here
(defn into-unique-id-4
[s1, [x2 & xs2]]
(cond (not x2)
,, s1
(empty? (filter (fn [x] (= (get x "id")
(get x2 "id")))
s1))
,, (into-unique-id (conj s1 x2) xs2)
:else
(into-unique-id s1 xs2)))
Run Code Online (Sandbox Code Playgroud)
接下来我看到了,而不是filter/ empty?我们可以使用内置some.
;; simplification -- we have idiomatic functions for this
(defn into-unique-id-5
[s1, [x2 & xs2]]
(cond (not x2)
,, s1
(some (fn [x] (= (get x "id")
(get x2 "id")))
s1)
,, (into-unique-id s1 xs2)
:else
,, (into-unique-id (conj s1 x2) xs2)))
Run Code Online (Sandbox Code Playgroud)
早期我注意到这实际上是reduce手工完成的,所以作为最后一步,我将把函数显示为减少.
;; structural simplification - we have idiomatic higher order functions
;; that we can use instead of recursion
(defn into-unique-id-6
[s1, coll]
(reduce
(fn [acc el]
(if (some (fn [x]
(= (get x "id")
(get el "id")))
acc)
acc
(conj acc el)))
s1
coll))
Run Code Online (Sandbox Code Playgroud)