Skip to content

Instantly share code, notes, and snippets.

@ericnormand
Created December 28, 2020 15:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ericnormand/3a39e9093692b1ee3dbbb612d739e468 to your computer and use it in GitHub Desktop.
Save ericnormand/3a39e9093692b1ee3dbbb612d739e468 to your computer and use it in GitHub Desktop.
408 - PurelyFunctional.tv Newsletter

Consecutive numbers

Write a function that takes a string of digits. Try to break up the digits into consecutive integers. If you can, return them, otherwise, return nil.

Examples

(consec "121314") ;=> [12 13 14]
(consec "121315") ;=> nil
(consec "444445") ;=> [444 445]
(consec "12") ;=> [1 2]
(consec "1") ; throws error

Thanks to this site for the challenge idea where it is considered Expert in JavaScript.

Please submit your solutions as comments on this gist.

@miner
Copy link

miner commented Dec 31, 2020

@steffan-westcott Good point about input such as "08" potentially being an issue for code using read-string as that would be an illegal octal number. Very large input strings could also cause errors if the code tries to read an integer that is bigger than a long. But I'm not going to support that.

@arthuronunes
Copy link

(require '[clojure.string :as str])

(defn ->sequence [value n]
  (let [initial-number (-> (subs value 0 n) Long/parseLong)]
    (loop [numbers-seq [initial-number]
           remaining-value (subs value n)]
      (if (empty? remaining-value)
        numbers-seq
        (let [last-number (last numbers-seq)
              next-number (inc last-number)
              next-number-str (str next-number)
              number-size (count next-number-str)]
          (when (str/starts-with? remaining-value next-number-str)
            (recur (conj numbers-seq next-number)
                   (subs remaining-value number-size))))))))

(defn consec [value]
  (let [start-with-zero? (str/starts-with? value "0")
        size (count value)
        limit (if start-with-zero? 1 (quot size 2))]
    (when (<= size 1)
      (throw (ex-info "String must be 2 or more characters" {:value value})))
    (loop [n 1]
      (when (<= n limit)
        (let [result (->sequence value n)]
          (if result
            result
            (recur (inc n))))))))

@MilanLempera
Copy link

(defn consec [str]
  (let [str-length (count str)]
    (when (< str-length 2)
      (throw (Exception. "consec requires at least 2 chars in input")))
    (let [max-length (quot str-length 2)
          lengths (range 1 (inc max-length))
          series (for [length lengths]
            (->> str
              (partition length)
              (map #(clojure.string/join "" %))
              (map #(Integer/parseInt %)))
          )
          consec-series (for [serie series
                              :let [snums (partition 2 1 serie)]
                              :when (every? (fn [[a b]] (= (inc a) b)) snums)]
        serie)]
      (first consec-series))))

@charJe
Copy link

charJe commented Feb 4, 2021

I chose to return nil on cases like "1" instead of error.

(defn consec [string]
  (some
   (fn [num]
     (loop [nums (list (Integer/parseInt (subs string 0 num)))
            num-string (subs string num)]
       (let [num (first nums)]
         (cond
           (and (empty? num-string)
                (< 1 (count nums)))
           , (reverse nums)
           :else
           , (let [next-num (Integer/parseInt (subs num-string 0 (count (str (+ 1 num)))))]
               (when (and (count (str (+ 1 num)))
                          (= (+ 1 num)
                             next-num))
                 (recur (cons next-num nums)
                        (subs num-string (count (str (+ 1 num)))))))))))
   (range 1 (+ 1 (quot (count string) 2)))))

@prairie-guy
Copy link

(defn split-by [ds k]                                                                                                                                 
  "(split-by "111213" 2) -> (11 12 13)"                                                                                                               
  (map (comp read-string join) (partition k ds)))

(defn ascending? [ns]                                                                                                                                 
  "(ascending? '(11 12 13)) -> (11 12 13)"                                                                                                            
  (if (= #{1} (set (map - (rest ns ) ns)))                                                                                                            
    ns))

(defn consec? [ds]
  "(consec? "111213") -> [11 12 13]"
  (->> (range 1 (inc (quot (count ds) 2)))
       (map (partial split-by ds))
       (filter ascending?)
       (first)
       vec))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment