我有一个seq (2 3 1 4)
。
我想迭代它,并且当下一个元素更小时,prev元素将替换elems另一个seq。 '( - 4 1)。
所以f('(2 3 1 4))=> (2( - 3 1)4)。我怎么写呢?
基本上 -
1)我想同时访问seq中的两个相邻元素。 2)编辑并返回该点的新seq。 3)继续处理新返回的seq。
通常实现上述3的机制是什么。 (map,reduce都让我一次只能访问一个elem。)
答案 0 :(得分:5)
这实际上并不是成对消费的问题,因为您对序列进行分区的方式取决于您对当前对的处理方式。请注意,有时您会从序列(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)
答案 1 :(得分:1)
我不确定我是否完全明白了你的问题,但我会抓住它。
首先我们声明一个var来保存你的seq:
(def myseq '(2 3 1 4))
然后,我们可以将相同的序列压缩在一起,但是在不同的起点。
这样我们就可以轻松访问前一个元素。这将返回一系列seqs,这就是为什么我们使用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)
希望这就是你所追求的目标。
答案 2 :(得分:1)
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]
答案 3 :(得分:1)
这是否解决了您的需求:
(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))