对于序列理解

时间:2018-04-25 09:24:54

标签: clojure

两天前我开始学习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版本完全相同?

2 个答案:

答案 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更有效,更简单。