从Clojure中的Atom过滤地图列表

时间:2018-08-21 22:01:44

标签: clojure

我正在开发一个小型社交媒体API,允许用户插入新的个人资料,将两个个人资料(例如朋友)连接在一起,然后根据“我的朋友的朋友”规则接收推荐。

现在,我正在尝试为Profile创建API。

我有一个原子,其中包含一个地图列表,每个配置文件一个。

(def profiles (atom ()))

(defn create [request]
 (swap! profiles conj {:id (get-in request [:body "id"])
                    :name (get-in request [:body "name"])
                    :age (get-in request [:body "age"])
                    :recommendable (get-in request [:body "recommendable"])
                    :friends (list) 
})
(created "")
)

当我遇到问题时,我正在尝试为API的GET http动词开发find-by-id。如何从上述列表中的映射中获取值,以便对其应用功能?

例如,在这里我试图使用过滤器功能仅向我返回包含给定ID的地图。但我不断收到错误消息:

(defn find-by-id [id]
  (filter #(= (:id %) id) profiles)
)

Dont know how to create ISeq from: clojure.lang.Atom

在我看来,过滤器不适用于Atom。

发生同样的事情:

(defn delete-by-id [id]
 (swap! profiles (remove #(= (:id %) id) profiles))
)

当我尝试使用@profiles时,结果是一个空数组。更糟糕的是,当我尝试使用REPL过滤器功能时,它工作得很好。

这让我想知道我在这里想念什么。

任何人都可以告诉我发生了什么事吗?

谢谢。

1 个答案:

答案 0 :(得分:0)

第一个失败的原因是,正如它所说的,原子不是filter所期望的序列。

filter之前,您需要先从原子中除去序列:

; I'm dereferencing the atom using @ to get the list of profiles that it holds
(defn find-by-id [id]
  (filter #(= (:id %) id) @profiles))

不过请注意,这不是最佳选择。您所依赖的状态profiles可能在看似随机的时间发生变化(如果您有异步进程swap!对它进行操作)。这可能会使调试复杂化,因为在将数据传递给filter之前无法很好地处理数据。对于函数来说,依靠profiles作为原子也是不好的,因为这与它的功能无关,您以后可以更改设计。使该函数完全依赖其参数并且不了解原子将是将来的证明。

(defn find-by-id [id profiles]
  (filter #(= (:id %) id) profiles))

; Then call it like this. I renamed your atom here
(find-by-id some-id @profile-atom)

您的第二个示例失败,因为swap!接受一个函数作为其第二个参数。我认为您打算使用reset!,它会更改原子的值,而不管其之前是什么:

(defn delete-by-id [id]
  (reset! profiles (remove #(= (:id %) id) @profiles)))

尽管如此,这也不是最佳选择。如果要基于先前状态更新原子,请改用swap!并提供更新功能:

(defn delete-by-id [id]
  (swap! profile-atom (fn [profiles] (remove #(= (:id %) id)) profiles)))

或更简洁地说:

(defn delete-by-id [id]
  (swap! profile-atom (partial remove #(= (:id %) id))))

我正在部分应用remove来实现功能。原子的旧状态作为最后一个参数传递给remove