Search code examples
clojuresequencefor-comprehension

Clojure For Comprehension example


I am using docjure and it needs a column map for its select-columns function. I would like to grab all my columns without having to specify it manually. How do I generate the following as a lazy infinite vector sequence [:A :B :C :D :E ... :AA :AB :AC .... :ZZ ... :XFD]?


Solution

  • Your question boils down to: "How do I convert a number to a base-26 string with the alphabet A-Z?".

    Here's one way to do that - probably not the most concise way, but making it more elegant is left as an exercise for the reader :).

    Assume that numbers 0-25 map to 'A'-'Z', 26 maps to 'AA', etcetera. First we define a function to-col that converts an integer to a column keyword. You can use that function to generate an infinite sequence.

    (defn to-col [num]
      (loop [n num s ()]
        (if (> n 25)
          (let [r (mod n 26)]
            (recur (dec (/ (- n r) 26)) (cons (char (+ 65 r)) s)))
          (keyword (apply str (cons (char (+ 65 n)) s))))))
    

    That gives you a way to generate an infinite sequence of column keywords:

    (take 100 (map to-col (range)))
    ;; => (:A :B :C :D :E :F :G :H :I :J :K :L :M :N :O :P :Q :R :S :T :U :V :W
    ;; :X :Y :Z :AA :AB :AC :AD :AE :AF :AG :AH :AI :AJ :AK :AL :AM :AN :AO :AP
    ;; :AQ :AR :AS :AT :AU :AV :AW :AX :AY :AZ :BA :BB :BC :BD :BE :BF :BG :BH
    ;; :BI :BJ :BK :BL :BM :BN :BO :BP :BQ :BR :BS :BT :BU :BV :BW :BX :BY :BZ
    ;; :CA :CB :CC :CD :CE :CF :CG :CH :CI :CJ :CK :CL :CM :CN :CO :CP :CQ :CR
    ;; :CS :CT :CU :CV)