两天前我开始学习Clojure,没有任何函数式编程经验。今天,在阅读编程Clojure 一书的阅读时,我遇到了一个问题。
关于转换序列。有一个例子:
(map #(format "<%s>%s</%s>" %1 %2 %1)
["h1" "h2" "h3" "h1"] ["the" "quick" "brown" "fox"])
产生结果:
-> ("<h1>the</h1>" "<h2>quick</h2>" "<h3>brown</h3>" "<h1>fox</h1>")
这对我来说并不难。实际上,当本书告诉我我们可以使用for
来产生序列理解时,问题就出现了,然后给我看了一个例子。这个例子有点简单,我完全可以理解它。
当我尝试重写我在for
时首次提到的示例时,问题就出现了。
我可以得到:
("<h1>the</h1>"
"<h1>quick</h1>"
"<h1>brown</h1>"
"<h1>fox</h1>"
"<h2>the</h2>"
"<h2>quick</h2>"
"<h2>brown</h2>"
"<h2>fox</h2>"
"<h3>the</h3>"
"<h3>quick</h3>"
"<h3>brown</h3>"
"<h3>fox</h3>"
"<h1>the</h1>"
"<h1>quick</h1>"
"<h1>brown</h1>"
"<h1>fox</h1>")
使用重写的代码:
(for [label ["h1" "h2" "h3" "h1"] word ["the" "quick" "brown" "fox"]]
(format "<%s>%s</%s>" label word label))
我被告知通常使用:when
条款可能会有所帮助,但我无法想到它。
如何使用for
重写代码,以便答案与map
版本完全相同?
答案 0 :(得分:5)
正如您在for
中有多个绑定时所见,它就像一个&#34;嵌套for循环&#34;在其他命令式语言中,就像你有label
的外部for循环和word
的内部for循环一样。所以你得到了两个系列的每一个组合&#39;值。
for (label in labels)
for (word in words)
print(word + " " + label);
我可以想象使用for
解决此问题的最简单方法也需要map
,因此我会使用您原来简单的map
解决方案。
(def pairs ;; a vector of tuples/pairs of labels/words
(map vector ["h1" "h2" "h3" "h1"] ["the" "quick" "brown" "fox"]))
;; (["h1" "the"] ["h2" "quick"] ["h3" "brown"] ["h1" "fox"])
(for [[label word] pairs] ;; enumerate each pair
(format "<%s>%s</%s>" label word label))
=> ("<h1>the</h1>" "<h2>quick</h2>" "<h3>brown</h3>" "<h1>fox</h1>")
当您将多个集合参数传递给map
时,映射函数会为每个映射步骤从每个集合中接收一个项目。如果您只有一个输入集合,则等效的for
看起来非常相似。
答案 1 :(得分:2)
for
在所有给定序列上生成笛卡尔积,因此获得相应对的一种方法是使用map-indexed
:
(for [[i label] (map-indexed vector ["h1" "h2" "h3" "h1"])
[j word] (map-indexed vector ["the" "quick" "brown" "fox"])
:when (= i j)]
(format "<%s>%s<%s>" label word label))
但这需要迭代超过16个值才能生成4个值,因此使用带有3个参数的map
更有效,更简单。