Hi all, I am trying to implement a function that splits any given sequence on a subsequence. I would like it to behave like this:
user> (split-at-subsequence [5 6] (range 10)) ((0 1 2 3 4) (7 8 9)) user> (split-at-subsequence [5 7] (range 10)) ((0 1 2 3 4 5 6 7 8 9)) user> (first (second (split-at-subsequence [1 2] (range)))) 3 The code I have so far inserts sentinels for the given subsequence and then returns chunks until a sentinel is found. (defn starts-with-subseq? "Returns true if the first sequence starts with the second one" [sub-seq coll] (let [pairs (map vector coll sub-seq) matching-pairs (take-while #(= (first %) (second %)) pairs)] (= (count matching-pairs) (count sub-seq)))) (defn- replace-subseq-with-sentinel [sub-seq sentinel coll] (lazy-seq (when-let [s (seq coll)] (if (starts-with-subseq? sub-seq s) (cons sentinel (replace-subseq-with-sentinel sub-seq sentinel (drop (count sub-seq) s))) (cons (first s) (replace-subseq-with-sentinel sub-seq sentinel (rest s))))))) (defn- split-at-sentinel [sentinel coll] (take-nth 2 (partition-by #(= sentinel %) coll))) (defn split-at-subsequence [sub-seq coll] (let [sentinel (Object.)] (->> (replace-subseq-with-sentinel sub-seq sentinel coll) (split-at-sentinel sentinel))) This does exactly what it should do, except for the fact that user> (first (second (split-at-subsequence [1 2] (range)))) never returns as it does not seem to be "lazy enough". What surprises me is that user> (def sentinel (Object.)) #'user/sentinel user> (take 5 (replace-subseq-with-sentinel [1 2] sentinel (range))) (0 #<Object java.lang.Object@272a335c> 3 4 5) works just fine, so the problem must be in my implementation of split-at-sentinel. I would be grateful for any pointers that might shed light on this behaviour. I am using clojure 1.3 if that is of any importance. Thanks for your time and may you have a nice day! -- Wolodja <babi...@gmail.com> 4096R/CAF14EFC 081C B7CD FF04 2BA9 94EA 36B2 8B7F 7D30 CAF1 4EFC
signature.asc
Description: Digital signature