我在编写优雅的drop-last-by
或butlast-by
函数时遇到了问题。
(drop-last-by odd? [2 1 9 4 7 7 3]) ; => (2 1 9 4)
(drop-last-by odd? [2 4]) ; => (2 4)
(drop-last-by odd? [9]) ; => ()
到目前为止我的工作有点但看起来有点笨拙,我想知道它是否可以在两三行中完成。
(defn drop-last-by [pred coll]
(let [p (partition-by pred coll)]
(apply concat (if (and (seq p) (pred (first (last p))))
(butlast p)
p))))
答案 0 :(得分:5)
由于drop-while
基本上已经完成了您的需求,并且由于您当前的解决方案已经不是懒惰,我会像这样写drop-last-by
:
(defn drop-last-by [pred coll]
(reverse (drop-while pred (reverse coll))))
答案 1 :(得分:1)
以下版本在问题规范允许的范围内是懒惰的:
任何不满足谓词的元素都会立即通过而不从源中读取任何其他元素;
只要从源中读入不满足谓词的元素,就会传递满足谓词的任何元素;
将删除任何满足谓词但未跟随不满足谓词的其他元素的元素。
此外,它可以用作(有状态)传感器;实际上,懒惰的seq版本是根据传感器和clojure.core/sequence
来实现的。
(defn drop-last-by
([pred]
(fn [rf]
(let [xs (volatile! [])]
(fn
([] (rf))
([result] (rf result))
([result input]
(if-not (pred input)
(do
(reduce rf result @xs)
(vreset! xs [])
(rf result input))
(do
(vswap! xs conj input)
result)))))))
([pred coll]
(sequence (drop-last-by pred) coll)))
在REPL:
(drop-last-by odd? [2 1 9 4 7 7 3])
;= (2 1 9 4)
(drop-last-by odd? [2 4])
;= (2 4)
(drop-last-by odd? [9])
;= ()
与其他传感器组合:
(into []
(comp (drop-while even?)
(drop-last-by odd?)
(map #(str "foo " %)))
[0 1 2 3 4 5])
;= ["foo 1" "foo 2" "foo 3" "foo 4"]