2

领悟:

(for [i (range 5])] i)

...产量:(0 1 2 3 4)

有没有一种惯用的方法来获得 (0 0 1 1 2 4 3 9 4 16) (即数字及其平方),主要使用for理解?

到目前为止,我发现的唯一方法是:

(apply concat (for [i (range 5)] (list i (* i i))))
4

3 回答 3

5

实际上,for如果您考虑为每个值应用每个函数(恒等式和平方),则使用 only 非常简单。

(for [i (range 5),             ; for every value
      f [identity #(* % %)]]   ; for every function
  (f i))                       ; apply the function to the value

 ; => (0 0 1 1 2 4 3 9 4 16)
于 2013-01-04T22:11:10.970 回答
4

由于 for 循环 x 次,它将返回 x 值的集合。多个嵌套循环(除非受whileor限制when)将给出 x * y * z * ... 结果。这就是为什么外部串联总是必要的。

输入和输出之间存在类似的相关性,地图。但是,如果在map中给出了多个集合,则返回集合中的值的数量是最小集合参数的大小。

=> (map (juxt identity #(* % %)) (range 5))
([0 0] [1 1] [2 4] [3 9] [4 16])

连接 map 的结果是如此常见的 mapcat 被创建。正因为如此,有人可能会争辩说 mapcat 是一种比 for 循环更惯用的方式。

=> (mapcat (juxt identity #(* % %)) (range 5))
(0 0 1 1 2 4 3 9 4 16)

虽然这只是 的简写apply concat (mapforcat但也可以轻松创建函数或宏。

但是,如果需要对集合进行累加,reduce 通常被认为是最惯用的。

=> (reduce (fn [acc i] (conj acc i (* i i))) [] (range 5))
[0 0 1 1 2 4 3 9 4 16]

for和选项都map意味着遍历一个集合两次,一次用于范围,一次用于连接结果集合。该reduce选项仅遍历范围。

愿意分享为什么“主要使用 for 理解”是一项要求?

于 2013-01-04T12:09:27.403 回答
2

我认为你做得对。

使用flatten可以实现稍微压缩的方式

(flatten (for [i (range 5)] [ i (* i i) ] ))

但我会摆脱for理解,只使用interleave

(let [x (range 5)
      y (map #(* % %) x)]
  (interleave x y))

免责声明:我只是一个业余的clojurist ;)

于 2013-01-04T12:04:56.443 回答