clojure - 当谓词为false时包含最后一项

时间:2015-06-18 16:37:43

标签: clojure

我有以下使用take-while

的功能
(defn process [[cash amount wrappers]]
  (let [bought (int (Math/floor (/ cash amount)))
        free (->>
              (iterate (partial unwrapper wrappers) bought)
              (take-while (partial (fn [w a]
                                     (prn (str "a = " a))
                                     (>= a w)
                                     ) wrappers)))]

我遇到的问题是我想在谓词为false时包含最后一项,但take-while不返回最后一项。

使用take-while或者我应该使用别的东西吗?

5 个答案:

答案 0 :(得分:2)

我在Leon Grapenthin's answer的评论中提到的partition-by方法尝试了一下。它通常可以正常运行,但是当你使用它所创建的一个分区时,partition-by会急切地评估下一个分区。因此虽然这应该是一种懒惰的方法,但它不如他的解决方案那么懒惰,因此无法处理无限序列的边缘情况,其中谓词映射看起来像(true true ... true false false....)仍然,有趣的问题到实验。

(defn take-while-plus-n 
  "Lazily returns successive items from coll while (pred item) returns true,
  then an additional n items. pred must partition coll into segments of finite length."
  [pred n coll]
  (if (pred (first coll))
    (let[[head & tails] (partition-by pred coll)]
      (lazy-cat head (->> tails flatten (take n))))
    (take n coll)))

我抛出了变量#"其他项目"因为我最终在两种情况下使用take

答案 1 :(得分:2)

您可以根据(defn take-while+ [pred coll] (lazy-seq (when-let [[f & r] (seq coll)] (if (pred f) (cons f (take-while+ pred r)) [f])))) 的来源

执行此类操作
dispatch_sync

答案 2 :(得分:1)

常用方法是使用split-with,它会在向量中返回take-whiledrop-while的结果。然后,您可以附加drop-while结果的第一个元素。

但是,它需要两次通过。你可能想写一个自定义的take-while ...

(defn take-while-and-one
  [pred coll]
  (lazy-seq
   (when-let [s (seq coll)]
     (if (pred (first s))
       (cons (first s) (take-while-and-one pred (rest s)))
       (list (first s))))))

答案 3 :(得分:0)

我首先创建一个谓词结果的向量,然后根据需要进行处理:

(def xx (range 10))
;=> (0 1 2 3 4 5 6 7 8 9)
(defn my-tst [arg]
  (< arg 5))
(def flags (mapv my-tst xx))
;=> [true true true true true false false false false false]
(def num-true (count (filter identity flags)))
num-true ;=> 5
(def num-keep (inc num-true))
num-keep ;=> 6
(def keepers (take num-keep xx))
keepers 
;=> (0 1 2 3 4 5)

答案 4 :(得分:0)

以下是换能器版本:

(defn take-while+
  ([pred]
   (fn [rf]
     (fn
       ([] (rf))
       ([result] (rf result))
       ([result input]
        (if (pred input)
          (rf result input)
          (reduced (conj! result input))))))))