您的位置:首页 > 运维架构

【Clojure】在loop-recur中实现多重循环

2016-07-09 01:14 405 查看

问题

在loop-recur中实现多重循环(里:如何造一个轮子)

描述

在loop-recur中使用一个N重循环是很痛苦的(脑细胞在燃烧),这时候可以使用一个生成N重循环下标列表的工具,在loop-recur中实现多重循环

代码

(defn smooth
[cur config]
(let [cur (reverse cur)
config (reverse config)
ps (map #(list % %2) cur config)]
(loop [carry 0
head (first ps)
tail (rest ps)
ret '()]
(if (nil? head)
ret
(let [[x y] head
the-carry (quot (+ carry x) y)
the-rest (mod (+ carry x) y)]
(recur the-carry (first tail) (rest tail) (conj ret the-rest)))))))

; only for test!
(smooth (map + [1 2 3] [3 9 9]) [10 10 10])
(smooth (map + [1 2 3] [1 1 1]) [10 10 10])
(smooth [0 2 2] [2 2 2])

(defn smooth-ex
[numbers limits]
(let [numbers (reverse numbers)
limits (reverse limits)
pairs (map #(list % %2) numbers limits)]
(loop [carry 0
head (first pairs)
tail (rest pairs)
ret '()]
(if (nil? head)
ret
(let [[number limit] head
the-carry (quot (+ carry number) limit)
the-rest (mod (+ carry number) limit)]
(recur the-carry (first tail) (rest tail) (conj ret the-rest)))))))

(defn looper-unit
[looper]
(if (= (count looper) 0)
'()
(let [zero-cnt (dec (count looper))]
(into '(1) (repeat zero-cnt 0)))))

(defn is-looper-end?
[looper looper-end]
(= (map inc looper) looper-end))

(defn looper-next
[looper looper-end]
(smooth (map + looper (looper-unit looper)) looper-end))

(defn looper-demo
[looper-end]
(loop [looper (repeat (count looper-end) 0) ret []]
(let [[i j] looper looper-string (str "row:" i " " "col:" j)]
(if (is-looper-end? looper looper-end)
(ret conj looper-string)
(recur (looper-next looper looper-end) (conj ret looper-string))))))

; just for test!
(map println (looper-demo [3 3]))


说明

smooth
: 类似大数加法中的进位操作,处理循环中下标的进位操作

smooth-ex
:
smooth
的容易阅读的版本 …

looper-unit
: 生成循环的递增单位,即一个形如
(0 ... 0 1)
的列表, 可能不含0

其他函数顾名思义,不解释了

核心思想即产生一系列列表,例如一个二重循环:

for(int i = 0; i < 2; ++i)
for(int j = 0; j < 2; ++j)
{ /* excuse me */}


其下标对应的序列为:

[ (0 0) (0 1) (1 0) (1 1) ]


那么对于任意循环,我们只需要生成该列表组就可以进行循环操作, 那么在哪里可以买到呢:

注意
(0 0)
(0 1)
的变化过程:

(= '(0 1) (map + '(0 0) '(0 1)))


(0 1)
(1 0)
的变化过程则较为复杂,但这一变化可以看作二进制下
01 + 01 => 10
的过程

宗上可以看出,生成列表的过程可以看作是一个N进制数字自增的过程,特别的是这里的每一个位可能对应不同的进制(比如上面那个循环把j的限制改成
j < 100
, 就变成了i是2进制,j是100进制的自增过程)

利用这一性质产生了如上的编码(轮子),具体使用方法参考
looper-demo
, 配合解构操作可以顺利获得各循环变量, 然后瞎鸡巴乱搞

最后需要注意的是,对循环的限制是左闭右开区间,
(looper-end [5 5])
得到的是一个 0-4 的二重循环

clojure多行注释太麻烦了,最后补上
(map println (looper-demo [3 3]))
的输出结果

; 不是代码 仅供参考

=> (map println (looper-demo [3 3]))

row:0 col:0
row:0 col:1
row:0 col:2
row:1 col:0
row:1 col:1
row:1 col:2
row:2 col:0
row:2 col:1
row:2 col:2
(nil nil nil nil nil nil nil nil nil)

; 最后的一串nil是prinln的返回值被map收集了, 因为这里我们需要的是副作用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: