Stop and split the generated sequence during repetitions - clojure

I am trying to make a sequence that will only generate values ​​until it finds the following conditions and returns the listed results:

case head =

  • 0 - return {: origin [all generated except 0]: pattern 0}
  • 1 - return {: origin nil: pattern [all-generated-values]}
  • repeat-value - {: origin [values-before-repeat]: pattern [values-after-repeat]

{

; n = int ; x = int ; hist - all generated values ; Keeps the head below x (defn trim-head [head x] (loop [head head] (if (> head x) (recur (- head x)) head))) ; Generates the next head (defn next-head [head xn] (trim-head (* head n) x)) (defn row [xn] (iterate #(next-head % xn) n)) ; Generates a whole row - ; Rows are a max of x - 1. (take (- x 1) (row 11 3)) 

Examples of stopped cases before reaching the end of the line:

[9 8 4 5 6 7 4] - '4' is repeated so STOP. Go back as a beginning and rest as a pattern.

 {:origin [9 8] :pattern [4 5 6 7]} 

[4 5 6 1] - found "1", therefore STOP, so return everything as a template

 {:origin nil :pattern [4 5 6 1]} 

[3 0] - found "0", so STOP

 {:origin [3] :pattern [0]} 

: else if sequences reach length x - 1:

 {:origin [all values generated] :pattern nil} 

Problem

I used some success with splitting to split the groups at the point where the duplicate value was found, but I would like to do it lazily. Is there a way I can use either condp or: while in a for loop to create a condition that separates when it finds duplicates?

Some attempts

 (take 2 (partition-by #(= 1 %) (row 11 4))) (for [p (partition-by #(stop-match? %) head) (iterate #(next-head % xn) n) :while (or (not= (last p) (or 1 0 n) (nil? (rest p))] {:origin (first p) :pattern (concat (second p) (last p))})) 

# Updates

What I really want to do is find out if the value was repeated and split seq without using an index. Is it possible? Something like that -

{

 (defn row [xn] (loop [hist [n] head (gen-next-head (first hist) xn) steps 1] (if (>= (- x 1) steps) (case head 0 {:origin [hist] :pattern [0]} 1 {:origin nil :pattern (conj hist head)} ; Speculative from here on out (let [p (partition-by #(apply distinct? %) (conj hist head))] (if-not (nil? (next p)) ; One partition if no repeats. {:origin (first p) :pattern (concat (second p) (nth 3 p))} (recur (conj hist head) (gen-next-head head xn) (inc steps))))) {:origin hist :pattern nil}))) 

}

+4
source share
2 answers

Impossible laziness: you can lazily consume new elements, but you must hang on all old elements to use them as a template, so in a sequence like this (iterate inc 2) , you should consume all available memory. In addition, for allows you to view only one element at a time, so it is not suitable for this task. However, writing it as a loop / replay, although a bit tedious, is not difficult. You did not specify what to return if the sequence ends before repeating, 1 or 0, so I just guessed.

In addition, your first example does not display correctly: it should stop at 1, not 4, so I adjusted your input. In addition to this, however, the question was asked very well: thank you for clearly asking the problem and describing what you encountered, as well as what you tried.

 (defn trim-head [coll] (loop [so-far [], indexes {}, index 0, coll (seq coll)] (if-not coll {:origin nil, :pattern so-far} ;; ?? not specified in question (let [x (first coll), xs (rest coll)] (if (contains? indexes x) {:origin (subvec so-far 0 (indexes x)) :pattern (subvec so-far (indexes x))} (case x 0 {:origin so-far, :pattern [x]} 1 {:origin nil, :pattern (conj so-far x)} (recur (conj so-far x) (assoc indexes x index) (inc index) (seq xs)))))))) user> (map trim-head [[9 8 2 4 5 6 7 4] [4 5 6 1] [3 0]]) ({:origin [9 8 2], :pattern [4 5 6 7]} {:origin nil, :pattern [4 5 6 1]} {:origin [3], :pattern [0]}) 
+1
source

What I really want to do is find out if the value was repeated and split seq without using an index. Is it possible?

I have fulfilled your updated requirements straight forward. In this case, split-with would be preferable to partition-by .

 ;;; find out if a value has repeated, but considering zero and one. (defn- generate "Returns a vector of [duplicate-value values-until-duplicate]. duplicate-value might be zero or one." [s] (->> [s [] #{0 1}] (iterate (fn [[[head & more] generated idx]] [more (conj generated head) (conj idx head)])) (take-while (comp seq first)) (drop-while (fn [[[head & _] _ idx]] (nil? (idx head)))) first ((juxt ffirst second)))) ;;; partition the seq without using the index. (defn partition-by-duplicate [s] (let [[pivot generated-values] (generate s)] (cond (= 0 pivot) {:origin generated-values, :pattern [0]} (= 1 pivot) {:origin nil, :pattern (conj generated-values 1)} pivot (->> generated-values (split-with (partial not= pivot)) (interleave [:pattern :origin]) (apply hash-map)) :else {:origin s, :pattern nil}))) 

Example:

 user> (map generate [[9 8 2 4 5 6 7 4] [4 5 6 1] [3 0]]) ([4 [9 8 2 4 5 6 7]] [1 [4 5 6]] [0 [3]]) user> (map partition-by-duplicate [[9 8 2 4 5 6 7 4] [4 5 6 1] [3 0]]) ({:pattern (9 8 2), :origin (4 5 6 7)} {:origin nil, :pattern [4 5 6 1]} {:origin [3], :pattern [0]}) 
+1
source

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


All Articles