我正在编写一个循环,它从向量中的字符串数据创建一个映射。在每次迭代中,我取向量中的最后一项,从中构造一个键和一个值,将它们与地图相关联,然后弹出刚刚从向量中记录到地图的项目。只要向量中仍有项目,此过程应不断重复,直到向量为空并且地图已满。
该功能如下:
(defn map-builder
"Transforms the vector of waterfalls into a map of waterfalls."
[input]
(loop [waterfall-db {}
vectorized-db input]
(let [key-str (last vectorized-db)]
key (->> key-str
(re-seq #"[0-9]+")
keyword)
val (subs key-str (+ 2 (.indexOf key-str ":"))))
(assoc waterfall-db key val)
(pop vectorized-db)
(if (> (count vectorized-db) 0)
(recur waterfall-db vectorized-db) waterfall-db)))
程序编译,但似乎无限循环。我做了一个测试,在一次迭代后使循环退出,并返回一个空映射(它应该有一个项目)。很明显,我不正确地将项目与地图关联起来,这让我觉得我必须也不正确地将项目与向量分离。我不知道自己在哪里出错了 - 我是否把我的当地人搞得不合适?
答案 0 :(得分:7)
在clojure中,数据结构不会就地更改:新的数据结构值是从旧的数据结构中计算出来的。
(pop vectorized-db)
弹出最后一个元素。 Clojure的pop
不能像这样工作,
但计算一个与vectorized-db
元素相同的新向量
但最后一个。(assoc waterfal-db key val)
。您需要做的是在recur
来电中传递新值。代码(我没有测试过,因为我没有它应该做的例子)转换为:
(defn map-builder
"Transforms the vector of waterfalls into a map of waterfalls."
[input]
(loop [waterfall-db {}
vectorized-db input]
(if (empty? vectorized-db)
waterfall-db
(let [key-str (last vectorized-db)
key (->> key-str
(re-seq #"[0-9]+")
keyword)
val (subs key-str (+ 2 (.indexOf key-str ":")))]
(recur (assoc waterfall-db key val) (pop vectorized-db))))))
答案 1 :(得分:6)
Juan Manuel发布的答案是正确的,但您可以考虑通过into
构建地图,这更简单:
(defn- make-kv [s]
(let [key (->> s (re-seq #"[0-9]+") first keyword)
val (-> s (.split ":") second string/trim)]
[key val]))
(defn map-builder [v]
(into {} (map make-kv v)))