Clojure take-while и N больше предметов

каков идиоматический способ в Clojure реализовать take-while-and-n-more ниже:

=> (take-while-and-n-more #(<= % 3)  1 (range 10))
(0 1 2 3 4)

моя попытка:

(defn take-while-and-n-more [pred n coll]
  (let
      [take-while-result (take-while pred coll)
       n0 (count take-while-result)] 
    (concat
     take-while-result
     (into [] (take n (drop n0 coll))))))

3 ответов


Я хотел бы использовать сплит-с, что эквивалентно получению результатов как take-while, так и drop-while для тех же параметров:

(defn take-while-and-n-more [pred n coll]
    (let [[head tail] (split-with pred coll)]
         (concat head (take n tail))))

еще один способ:

(defn take-while-and-n-more [pred n coll]
  (let [[a b] (split-with pred coll)]
    (concat a (take n b)))) 

следующий код является модифицированной версией Clojures take-while. Где Clojures take-while возвращает nil в качестве случая по умолчанию (когда предикат не совпадает), этот вызывает take чтобы взять дополнительные элементы после сбоя предиката.

обратите внимание, что в отличие от версии с использованием split-with, эта версия проходит последовательность только один раз.

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