用于序列理解的clojure一次添加两个元素

时间:2013-01-04 11:32:28

标签: clojure

理解:

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

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

是否有一种惯用的方式来获得(0 0 1 1 2 4 3 9 4 16)(即数字和它们的方块)主要使用 理解?

到目前为止,我找到的唯一方法就是:

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

3 个答案:

答案 0 :(得分:5)

实际上,如果您考虑为每个值应用每个函数(标识和正方形),则仅使用for非常简单。

(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)

答案 1 :(得分:4)

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

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

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

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

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

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

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

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

formap选项都意味着遍历集合两次,一次遍历范围,一次用于连接生成的集合。 reduce选项仅遍历范围。

谨慎分享为什么“主要使用理解”是一项要求?

答案 2 :(得分:2)

我认为你做得对。

使用展平

可以实现略微压缩的方式
(flatten (for [i (range 5)] [ i (* i i) ] ))

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

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

免责声明:我只是一名业余背包徒步旅行者;)