在Clojure中,函数for可用于迭代嵌套序列。想象一个有x、y和z轴的3D空间:
(for [x (range 10)
y (range 5)
z (range 2)]
[x y z])上面的代码将产生一个代表长方体内部所有可能位置的向量序列。(仅限于索引为自然数的位置)
有没有人知道让它更通用的好方法?这意味着,如果你不是有3个维度,而是n个维度,就能让它工作。
发布于 2016-03-09 01:45:12
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)))))发布于 2016-03-09 04:47:49
另一种方法(可能比cartesian-product更糟糕,但仍然很好地展示了clojure的宏的强大功能):
(defmacro product [& colls]
(let [names (repeatedly (count colls) #(gensym "var"))]
`(for ~(vec (interleave names colls))
~(vec names))))它只是为任意数量的colls生成这个for列表理解。例如:
(product (range 3) [:a :b :c] (range 2))将扩展为以下内容:
(for [var19715 (range 3) var19716 [:a :b :c] var19717 (range 2)]
[var19715 var19716 var19717])发布于 2016-03-09 05:08:17
for是一个宏,它的主体表达式可以包含任意代码,如do块或IO调用:
(for [x (range 3)]
(do
(prn x)
x))假设所需的主体表达式始终采用[x y z ... n]的形式,并且输入为正范围
如何创建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却很渴望。使用doall包装for将强制执行计算,但使用瞬态的loop可能会执行得更好。
https://stackoverflow.com/questions/35874072
复制相似问题