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

来源:互联网 发布:淘宝网邮票真假 编辑:程序博客网 时间:2024/06/04 18:12

问题

在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:0row:0 col:1row:0 col:2row:1 col:0row:1 col:1row:1 col:2row:2 col:0row:2 col:1row:2 col:2(nil nil nil nil nil nil nil nil nil); 最后的一串nil是prinln的返回值被map收集了, 因为这里我们需要的是副作用
0 0
原创粉丝点击