我想在clojure中编写一个函数,它会返回一个地图,给出一个形式为“key1 $ value1,key2 $ value2”的字符串。我想出了这个。
(defn get-map
"Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'"
[line]
(let [result {}]
(for [item (split line #",")]
(let [pair (split item #"\$")]
(assoc result (nth pair 0)
(if (= (.size pair) 2) (nth pair 1) ""))))))
虽然它有效但这段代码的唯一问题是它会在列表中返回地图。
=>(get-map "key1$value1,key2,value2")
({"key1" "value1"} {"key2" "value2"})
我试图将结果作为第一个let表单的最后一个表达式返回,但结果是一个空映射。
(defn get-map
"Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'"
[line]
(let [result {}]
(for [item (split line #",")]
(let [pair (split item #"\$")]
(assoc result (nth pair 0)
(if (= (.size pair) 2) (nth pair 1) ""))))
result))
=>(get-map "key1$value1,key2,value2")
{}
两个问题 -
此外,如果您有建议以更好,更惯用的方式编写相同的功能,那将是值得赞赏的。
答案 0 :(得分:2)
(defn get-map
"Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'"
[line]
(->> (clojure.string/split line #",")
(mapcat #(clojure.string/split % #"\$"))
(apply hash-map)))
user> (get-map "key1$value1,key2$value2")
{"key1" "value1", "key2" "value2"}
对问题1的回答/提示: 总是返回一个序列。这是Clojure中的列表理解。
对问题2的回答/提示: Clojure的数据结构是不可变的。这意味着在现有地图上关联不会改变现有地图,但会返回一个新地图。
答案 1 :(得分:2)
for
表单执行惰性列表解析,因此不适合顺序更新结构。您可以使用for
生成配对列表,并使用reduce
将它们打包到地图中。或者,使用into
进行缩减:
(defn get-map [line]
(into {}
(for [item (split line #",")]
(split item #"\$"))))
使用re-seq
的另一种可能的实现方式:
(defn get-map [s]
(into {} (map #(subvec % 1) (re-seq #"([^\$]+)\$([^,]+),*" s))))
答案 2 :(得分:2)
在Clojure中,for
不是一个循环,它是一个列表理解。基本上它需要你的每个项目
收集并将其绑定到您指定的任何名称(在本例中为item
),然后进行评估
表达式(在这种情况下为let [pair...
)。每个评估的结果都以a。形式返回
序列
例如:
(for [item (split "key1$value1,key2$value2" #",")]
item)
;returns: ("key1$value1" "key2$value2")
在你的函数中,for
实际创建了列表。由let
绑定的名称是不可变的
所以每次for
评估它的表达式result
仍然是一张空地图。这就是你得到的原因
每个地图中都有一个条目的地图列表。
这是一种生成使用nth
的未找到功能的键值对列表的方法
如果缺少$,则提供默认值:
(for [item (split "key1$value1,key2$value2,key3" #",")]
(let [pair (split item #"\$")]
[(nth pair 0) (nth pair 1 "")]))
;returns: (["key1" "value1"] ["key2" "value2"] ["key3" ""])
然后您可以使用into
将其转换为地图。这是完整的功能:
(defn get-map
"Returns a map of key value pairs from a string formatted in the form 'key1$value1,key2$value2'"
[line]
(into {}
(for [item (split line #",")]
(let [pair (split item #"\$")]
[(nth pair 0) (nth pair 1 "")]))))