几周前我已经开始进行一些函数式编程,并且我正在尝试从一个映射列表到一个考虑clojure中特定键的列表执行映射。
我的地图列表如下:'({:a "a1" :b "b1" :c "c1"} {:a "a2" :b "b2" :c "c2"} {:a "a3" :b "b3" :c "c3"})
我想要得到的输出是:'("b1" "b2" "b3")
。
我尝试了以下操作:
(doseq [m maps]
(println (list (get m :b))))
我的输出是一个列表列表(在为每次迭代创建一个列表时,这是预期的)。所以我的问题是,如何将其简化为一个列表?
更新
只需尝试以下操作:
(let [x '()]
(doseq [m map]
(conj x (get m :b))))
但是,它仍然无法正常工作。我不明白这一点,因为我期望将元素添加到一个空列表中
答案 0 :(得分:7)
这是生产Clojure代码中非常常见的模式,因此是学习的好地方。通常,请查看https://clojure.org/reference/sequences上有关序列的文档,当遇到类似任务时,请查看哪种模式最适合并探索该组中的功能。在这种情况下,它是“处理序列的每个项目以创建新的序列”,并且列出的第一项是map
您的示例可能像
(map :b my-data)
答案 1 :(得分:0)
您有正确的想法,但使用的是错误的功能。 doseq
仅用于副作用,并且始终返回nil
。您要查找的函数是for
,它将一个序列作为输入并返回另一个序列作为输出。我通常更喜欢for
而不是类似的map
,因为for
可以命名循环变量:
(def data-list
[{:a "a1" :b "b1" :c "c1"}
{:a "a2" :b "b2" :c "c2"}
{:a "a3" :b "b3" :c "c3"}])
(let [result (vec (for [item data-list]
(:b item)))]
(println result) ; print result
result) ; return result from `let` expression
result => ["b1" "b2" "b3"]
相反,您可以这样做:
(println
(doseq [item data-list]
(println (:b item))))
您可以看到doseq
与for
的区别:
b1 ; loop item #1
b2 ; loop item #2
b3 ; loop item #3
nil ; return value of doseq
有关在线详细信息,请参见https://www.braveclojure.com/,并购买《 Getting Clojure》等一本好书(或5本)。
答案 2 :(得分:0)
(doseq [m maps] (println (list (get m :b))))
在短短的两行中,您打破了函数式编程的一些一般规则:
doseq
之类具有副作用的机制。尽管如此,您离解决方案也不远。 doseq
本质上是for
的一个版本,会丢弃其结果。如果将doseq
替换为for
,并且摆脱println
和list
,我们得到
=> (for [m maps] (get m :b))
("b1" "b2" "b3")