用id替换向量中的项目

时间:2018-04-13 15:41:36

标签: clojure

(defonce channels (atom []))

(defn register-channel! [id tag channel]
  (swap! channels conj [id tag channel]))

(register-channel! "456" :player {})

@channels ;; => [["456" :player {}]]

id和tag是数据的索引,id是唯一的,tag不是。 我可以将conj个新项目发送到频道。但是,使用现有ID调用register-channel!不会conj新项目,而是应更改现有项目的第三个元素channel。

这就是我所拥有的,有效的方法:

(defn register-channel! [id tag channel]
  (let [without-id (remove #(= id (first %)) @channels)
        with-id (conj without-id [id tag channel])]
    (reset! channels with-id)))

我非常确定有更优雅的方式:)

请注意,我正在使用向量集合,因为我只有3个元素,如果没有明显的性能损失,我可以使用映射。但是,我需要编写函数来通过id或通过标记的通道来查找通道,例如

(defn one-by-id [id] (first (filter #(= id (first %)) @channels)))
(defn many-by-tag [tag] (filter #(= tag (second %)) @channels))

1 个答案:

答案 0 :(得分:2)

如果你真的需要频道作为成对矢量,你可以像这样添加或替换新频道:

> (vec (assoc (into {} [[:a 1]]) :a 2))
[[:a 2]]

> (vec (assoc (into {} [[:a 1]]) :b 2))
[[:a 1] [:b 2]]

但这引出了一个问题,即你是否宁愿让频道本身成为地图。

将原子定义为空地图并完成工作!

(defonce channels (atom {}))

(defn register-channel! [id channel]
  (swap! channels conj [id channel]))

> (register-channel! "456" {:a 1})
{"456" {:a 1}}
> (register-channel! "457" {:a 1})
{"456" {:a 1}, "457" {:a 1}}
> (register-channel! "457" {:a 2})
{"456" {:a 1}, "457" {:a 2}}