除了谓词为真的集合的最后元素之外的所有元素的序列

时间:2016-03-27 22:20:05

标签: clojure

我在编写优雅的drop-last-bybutlast-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))))

2 个答案:

答案 0 :(得分:5)

由于drop-while基本上已经完成了您的需求,并且由于您当前的解决方案已经不是懒惰,我会像这样写drop-last-by

(defn drop-last-by [pred coll]
  (reverse (drop-while pred (reverse coll))))

答案 1 :(得分:1)

以下版本在问题规范允许的范围内是懒惰的:

  1. 任何不满足谓词的元素都会立即通过而不从源中读取任何其他元素;

  2. 只要从源中读入不满足谓词的元素,就会传递满足谓词的任何元素;

  3. 将删除任何满足谓词但未跟随不满足谓词的其他元素的元素。

  4. 此外,它可以用作(有状态)传感器;实际上,懒惰的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"]