Clojure list manipulation

I want to take a list and generate subsequences as follows:

(subs '(1 2 3)) ; should evaluate to ((1) (1 2) (1 2 3) (2) (2 3) (3)) 

and yes, order matters. I might have missed something obvious, but I'm stuck. Bonus points for beautiful decisions!

+4
source share
6 answers

One more step, a little shorter.

 (defn subs4 [coll] (mapcat #(reverse (take (count %) (iterate butlast %))) (take (count coll) (iterate rest coll)))) 
+4
source
 (defn subseqs [coll] (lazy-seq (when-let [s (seq coll)] (let [n (inc (count coll))] (concat (map take (range 1 n) (repeat s)) (subseqs (rest s))))))) 

nil independent variation of the ponzao response.

Edit: another one using reductions .

 (defn subseqs [coll] (lazy-seq (when-let [s (seq coll)] (let [fst (first s) rst (rest s)] (concat (reductions conj [fst] rst) (subseqs rst)))))) 

Please note that this version is full of laziness! Well, until you go through the first complete subsequence. It is as lazy as you can get.

The next version is also completely lazy, but at startup it constructs reductions only once.

 (defn subseqs [coll] (let [step (fn step [subcolls] (lazy-seq (when-let [s (next subcolls)] (concat s (step (map next s))))))] (step (reductions conj [] coll)))) 
+4
source
 (defn subseqs [[x & xs :as coll]] (when (seq coll) (lazy-cat (for [n (range 1 (inc (count coll)))] (take n coll)) (subseqs xs)))) 
+3
source

My version with recursion:

 (defn my-subs ([lst] (my-subs lst (count lst))) ([lst, len] (when (> len 0) (concat (for [i (range 1 (+ 1 len))] (take i lst)) (my-subs (rest lst) (- len 1)))))) (my-subs '(1 2 3)) ; => ((1) (1 2) (1 2 3) (2) (2 3) (3)) 
+3
source
 (defn subs3 [coll] (apply concat [] (map #(reverse (for [x (iterate butlast %) :while (not-empty x)] x)) (for [x (iterate rest coll) :while (not-empty x)] x)))) 
+3
source

No recursion needed, just nested ole point for loops

  (defn subs [seq] (let [c (count seq)] (remove empty? (for [x (range c) y (range (- (inc c) x))] (take y (drop x seq)))))) 

and one more

 (defn subs [seq] (letfn [(take-len [fs] (take (count s) (iterate fs)))] (mapcat #(reverse (take-len butlast %)) (take-len next seq)))) 

Just noticed that this is about the same as the eis version. I tried to collapse my own version of butlast (due to symmetry with the "iteration of the next"), but none of them made things shorter than nested for loops. Until I discovered that he stayed on clojuredocs.

In any case, try problems with 4clojure. The inability to get to the answers really makes you find the answer, any answer that works, and if you do / did, you will find it more elegant. And if you had no idea, usually the responses of other users will be highlighted or inspired after you allow it.

+2
source

Source: https://habr.com/ru/post/1393128/


All Articles