2012-01-26 3 views
4

Я хочу взять список и генерировать подпоследовательности, таким образом:Clojure список манипуляция

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

и да, порядок имеет значение. Я мог бы пропустить что-то очевидное, но я застрял. Бонусные баллы за прекрасные решения!

+1

Подумайте, рекурсивно. Если бы вы могли генерировать все подпоследовательности '(2 3)', могли бы вы получить все подпоследовательности '(1 2 3)'? – Peteris

ответ

4

Другой взять, немного короче.

(defn subs4 [coll] 
    (mapcat #(reverse (take (count %) (iterate butlast %))) 
     (take (count coll) (iterate rest coll)))) 
2

Нет рекурсии требуется, только вложенный равнина оле для петель

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

и еще один

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

Просто заметил, что это примерно так же, как электронная является: версия. Попробовал свернуть мою собственную версию butlast (из-за симметрии с «итерацией следующего»), но ни одна из них не делала вещи более краткими, чем вложенные для циклов. До тех пор, пока я не обнаружил, что он остался на clojuredocs.

В любом случае, попробуйте проблемы с 4clojure. Невозможность дойти до ответов действительно заставляет вас найти ответ, любой ответ, который работает, и если вы это сделаете/сделали, вы найдете более элегантный. И если вы не знаете, обычно есть ответы других пользователей, которые просветят или вдохновят вас после того, как вы ее разрешите.

+0

Я нашел 'butlast' на [Clojure cheatseet] (http://clojure.org/cheatsheet), который действительно крут. – MisterMetaphor

3
(defn subseqs 
    [[x & xs :as coll]] 
    (when (seq coll) 
    (lazy-cat 
    (for [n (range 1 (inc (count coll)))] 
     (take n coll)) 
    (subseqs xs)))) 
3

Моя версия с рекурсией:

(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)) 
4
(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 -safe вариация ответа ponzao в.

Редактировать: Еще один, используя 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)))))) 

Обратите внимание, что эта версия полностью ленива! Ну, пока вы не пройдете первую полную подпоследовательность. Это так же лениво, как вы можете получить.

Следующая версия также полностью ленива, но конструирует reductions только один раз при запуске.

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

Хороший улов, я исправлю это в своем ответе. – ponzao

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