在Clojure中,函数for
可用于迭代嵌套序列。想象一下具有x轴,y轴和z轴的3D空间:
(for [x (range 10)
y (range 5)
z (range 2)]
[x y z])
上面的代码会生成一系列向量,表示长方体内的所有可能位置。 (当然,限于指数是自然数的位置)
有人知道一个更好的方法吗?意思是,如果你没有3个但是有n个维度,那么它就可以了。
答案 0 :(得分:5)
Most approaches似乎正如您所做的那样使用for
。你似乎在寻找的是cartesian product。在clojure.math.combinatorics中有一个计算笛卡尔积的函数。
(cartesian-product (range 10) (range 5) (range 2))
(apply cartesian-product (map range [10 5 2]))
(apply cartesian-product (repeatedly n #(range 3)))
如果您不想包含其他图书馆,this question会提供一些您可以使用和/或学习的有趣答案。
截至2016年3月,这是clojure.math.combinatorics/cartesian-product
的来源:
(defn cartesian-product
"All the ways to take one item from each sequence"
[& seqs]
(let [v-original-seqs (vec seqs)
step
(fn step [v-seqs]
(let [increment
(fn [v-seqs]
(loop [i (dec (count v-seqs)), v-seqs v-seqs]
(if (= i -1) nil
(if-let [rst (next (v-seqs i))]
(assoc v-seqs i rst)
(recur (dec i) (assoc v-seqs i (v-original-seqs i)))))))]
(when v-seqs
(cons (map first v-seqs)
(lazy-seq (step (increment v-seqs)))))))]
(when (every? seq seqs)
(lazy-seq (step v-original-seqs)))))
答案 1 :(得分:1)
另一种方法(可能比cartesian-product
更差,但仍然很好地显示了clojure宏的强大功能):
(defmacro product [& colls]
(let [names (repeatedly (count colls) #(gensym "var"))]
`(for ~(vec (interleave names colls))
~(vec names))))
它只为任意数量的coll生成此for
列表解析。例如:
(product (range 3) [:a :b :c] (range 2))
将扩展为以下内容:
(for [var19715 (range 3) var19716 [:a :b :c] var19717 (range 2)]
[var19715 var19716 var19717])
答案 2 :(得分:0)
for
是一个宏,它的正文表达式可以包含任意代码,例如do
块或IO调用:
(for [x (range 3)]
(do
(prn x)
x))
假设所需的身体表情始终采用[x y z ... n]
的形式且输入为正范围
(defn matrix [h & t]
(if (some? t)
(for [d (range h)
ds (apply matrix t)]
(into [d] ds))
(map vector (range h))))
这有点天真,但似乎做了这个工作:
(matrix 3) ;; => (map vector (range 3))
;; => ([0] [1] [2])
(matrix 3 2) ;; => (for [d (range 3) ds (apply matrix '(2))] (into [d] ds))
;; => ([0 0] [0 1] [1 0] [1 1] [2 0] [2 1])
(matrix 3 2 4)
;; => ([0 0 0] [0 0 1] [0 0 2] [0 0 3] [0 1 0] [0 1 1] [0 1 2] [0 1 3]
;; [1 0 0] [1 0 1] [1 0 2] [1 0 3] [1 1 0] [1 1 1] [1 1 2] [1 1 3]
;; [2 0 0] [2 0 1] [2 0 2] [2 0 3] [2 1 0] [2 1 1] [2 1 2] [2 1 3])
我说天真是因为for
很懒,但into
很渴望。将for
与doall
一起包装会强制进行评估,但使用瞬变的loop
可能会更好。