2013-09-06 9 views
6

Qual è il modo idiomatico in Clojure per attuare take-while-and-n-more di seguito:Clojure take-po 'e n più elementi

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

La mia prova è:

(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)))))) 

risposta

9

userei split-with, che è l'equivalente di ottenere risultati di entrambi take-po 'e drop-mentre per gli stessi parametri:

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

Il seguente codice è una versione modificata di Clojures take-while . Dove Clojures take-while restituisce nil come un caso predefinito (quando il predicato non corrisponde), questo invoca take per prendere gli elementi aggiuntivi dopo che il predicato ha esito negativo.

Si noti che a differenza delle versioni che utilizzano split-with, questa versione attraversa la sequenza solo una volta.

(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))))) 
+0

concat restituisce una sequenza lenta – soulcheck

+0

Hai ragione. Ho modificato la mia risposta. Tuttavia, split-with risulterà nel percorrere due volte la parte di corrispondenza del predicato della sequenza. –

3

ancora un altro modo:

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