我有一个 seq (2 3 1 4)
。
我想遍历它,并且无论下一个元素小于哪个元素,那么 prev 元素都会替换两个 elems 另一个 seq。'(- 4 1)。
所以 f('(2 3 1 4)) => (2 (- 3 1) 4)。我该怎么写?
基本上 -
1)我想同时访问一个序列中的两个相邻元素。2)此时编辑并返回一个新的序列。3) 继续处理新返回的seq。
一般实现上述3的机制是什么。(map,reduce 都让我一次只能访问一个元素。)
我有一个 seq (2 3 1 4)
。
我想遍历它,并且无论下一个元素小于哪个元素,那么 prev 元素都会替换两个 elems 另一个 seq。'(- 4 1)。
所以 f('(2 3 1 4)) => (2 (- 3 1) 4)。我该怎么写?
基本上 -
1)我想同时访问一个序列中的两个相邻元素。2)此时编辑并返回一个新的序列。3) 继续处理新返回的seq。
一般实现上述3的机制是什么。(map,reduce 都让我一次只能访问一个元素。)
这实际上不是成对消耗的问题,因为您如何划分序列取决于您对当前对执行的操作。请注意,有时您会从序列中消费一项2 3
( ),但有时您会消费两项( 3 1
)。
因此,您不能使用任何在 clojure ( , 等) 中创建滑动窗口的常用(partition 2 1 coll)
方法(map fn coll (rest coll))
。您需要使用显式递归的东西。
你的算法应该是这样的:
(- first second)
; 用剩余项目递归这是该算法的惰性实现。你也可以用recur
一个累加器来做到这一点——它不会懒惰,但它仍然可以工作。
(defn combine-if-gt-next
[[f s & r]]
(cond
(nil? f) nil
(nil? s) (cons f nil)
(> f s) (cons (list '- f s) (lazy-seq (combine-if-gt-next r)))
true (cons f (lazy-seq (combine-if-gt-next (cons s r))))))
例子:
(combine-if-gt-next '(2 3 1 4)) ; your example
;; (2 (- 3 1) 4)
(combine-if-gt-next [])
;; nil
(combine-if-gt-next [1 2 3])
;; (1 2 3)
(combine-if-gt-next [2 3 4 1])
;; (2 3 (- 4 1))
(combine-if-gt-next [2 3 4 1 4])
;; (2 3 (- 4 1) 4)
(combine-if-gt-next [2 1 4 1 4 5 1])
;; ((- 2 1) (- 4 1) 4 (- 5 1))
(combine-if-gt-next [5 4 3 2 1])
;; ((- 5 4) (- 3 2) 1)
我不确定我是否完全理解您的问题,但我会尝试一下。
首先我们声明一个 var 来保存你的序列:
(def myseq '(2 3 1 4))
然后,我们可以将相同的序列压缩在一起,但起点不同。这样我们就可以轻松访问前一个元素。这将返回一个 seq 的 seq,这就是我们用来mapcat
将结果连接到一个列表中的原因:
(mapcat
(fn [prev curr]
(if (< prev curr)
[`(~'- ~curr ~prev)]
[curr]))
myseq (drop 1 myseq))
;; evaluates to((- 3 2) 1 (- 4 1))
或者,如果您在我提出的第二个输出之后:
(mapcat
(fn [prev curr]
(if (< prev curr)
[`(~'- ~curr ~prev)]
[]))
myseq (drop 1 myseq))
;; evaluates to ((- 3 2) (- 4 1))
希望这可以帮助。
更新:
好的,这给了你想要的输出:
(mapcat
(fn [prev curr idx]
(cond
(< curr prev) [`(~'- ~prev ~curr)]
(= (+ idx 2) (count myseq)) [curr]
:else [prev]))
myseq (drop 1 myseq) (range (count myseq)))
;; evaluates to (2 (- 3 1) 4)
希望这就是你所追求的。
partition和 partition-all 让您可以将一个序列转换为一批元素,使用(partition 2 1 data)
可以让您在一个滑动窗口对上进行迭代。
(def data '(2 3 1 4))
(loop [res [] pairs (partition-all 2 1 data)]
(if-let [[l r] (first pairs)]
(if (and r (< r l))
(recur (conj res ['- l r]) (drop 2 pairs))
(recur (conj res l) (rest pairs)))
res))
;; returns [2 [- 3 1] 4]
这是否解决了您的需求:
(defn my-fun [[f s & r]]
(let [[flip next] (cond (and (nil? f) (nil? s)) ['() r]
(nil? f) [(list s) r]
(nil? s) [(list f) r]
(< s f) [(list (list (- f) s)) r]
:else [(list f) (cons s r)])]
(if (nil? r)
(concat flip next)
(concat flip (my-fun next)))))
(my-fun '(2 3 1 4))
=> (2 (-3 1) 4)
(my-fun '(6 3 5 4))
=> ((-6 3) (-5 4))