这几天试着用 PigPen 写一些脚原本处理一些数据。过程当中遇到一个问题,感受永别的语言写起来必定很简单,可是因为用 Clojure 写代码的经验少,一时不知道怎么用 Clojure 的方法来实现。git
为了方便讲清楚问题,先对问题进行简化:github
有一个数组 [1 2 3 7 8 9 13 13 14],我想计算相邻两个元素的差,若是大于3,就把以前的元素拿出来做为一个分组,最后返回一个包含全部分组的数组。如刚才那个数组返回的结果但愿是 [[1 2 3] [7 8 9] [13 13 14]]。数组
若是用 Lua,实现很简单:数据结构
function my_partition(arr) local grps, cur_grp, last_idx = {}, {}, 1 for idx,item in ipairs(arr) do if item - arr[last_idx] > 3 then table.insert(grps, cur_grp) cur_grp = {} table.insert(cur_grp, item) else table.insert(cur_grp, item) end last_idx = idx end table.insert(grps, cur_grp) return grps end
可是若是用 Clojure 来实现,感受不太适合定义像 grps
,cur_grp
,last_idx
这样的状态变量,由于 Clojure 中不少数据结构都是 immutable 的,是尽可能避免状态变量的。并且刚开始写 Clojure 就带着坏习惯,写惯了以后就很难改过来了。全部宁肯刚开始慢一点,也尽可能避免坏习惯。因此就向 cn-clojure邮件组 发了一封邮件问这个问题。app
<!--more-->google
最早回复的是 Dennis,给出了两个方案:atom
(let [prev (atom 0)] (partition-by #(let [v @prev] (reset! prev %) (> (- % v) 3)) [1 2 3 7 8 9 13 13 14]))
这个方案中仍是用到了一个状态变量 prev
,还有另外一个方案:lua
(defn my-partition ([coll] (my-partition [] coll)) ([xs coll] (lazy-seq (when-let [s (seq coll)] (let [fst (first s) sec (second s)] (if (or (nil? sec) (> (- sec fst) 3)) (cons (conj xs fst) (my-partition [] (next s))) (my-partition (conj xs fst) (next s))))))))
这是个 lazy-seq
的方法,利用相似尾递归的方法返回 lazy 的分组,这种方法和 clojur.core 里的 partition-by
方法的实现相似,也是我看了 partition-by
的实现后想到的一种方法,可是本身没写下来。.net
还有其余一些同窗的答案:code
(reduce (fn [result i] (let [prev (-> result last last)] (if (and prev (<= (- i prev) 3)) (conj (pop result) (conj (peek result) i)) (conj result [i])))) [] [1 2 3 7 8 9 13 13 14])
还有:
(let [x [1 8 3 6 10 14 11 15]] (->> (partition 2 1 x) (map #(- (second %) (first %))) (map (partial < 3)) (interleave x ) (apply vector) (#(conj % (last x))) (partition-by #(or (number? %) (false? %))) (map #(filter number? %)) (filter seq)))
还有:
(defn f [coll] (->> (conj coll (last coll)) (partition 2 1) (keep-indexed #(if (> (- (second %2) (first %2)) 3) %1)) (cons -1) (partition 2 1) (map #(- (second %) (first %))) (reduce #(concat (butlast %1) (split-at %2 (last %1))) [coll])))
每一个看完后都感受受益不浅。