Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure take-while and n more items

Tags:

clojure

What's the idiomatic way in Clojure to implement take-while-and-n-more below:

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

My try is:

(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))))))
like image 608
Marcus Junius Brutus Avatar asked Sep 06 '13 14:09

Marcus Junius Brutus


3 Answers

I would use split-with, which is equivalent of getting results of both take-while and drop-while for the same parameters:

(defn take-while-and-n-more [pred n coll]
    (let [[head tail] (split-with pred coll)]
         (concat head (take n tail))))
like image 199
soulcheck Avatar answered Nov 03 '22 06:11

soulcheck


Yet another way:

(defn take-while-and-n-more [pred n coll]
  (let [[a b] (split-with pred coll)]
    (concat a (take n b)))) 
like image 32
leonardoborges Avatar answered Nov 03 '22 07:11

leonardoborges


The following code is a modified version of Clojures take-while. Where Clojures take-while returns nil as a default case (when the predicate does not match), this one invokes take to take the the additional items after the predicate fails.

Note that unlike versions using split-with, this version traverses the sequence only once.

(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)))))
like image 2
Leon Grapenthin Avatar answered Nov 03 '22 06:11

Leon Grapenthin