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]?
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)
The essential clojure function for corecursion (and "tying the knot" is about it, no?) is iterate:
(def abc (map (comp str char) (range 65 91)))
(defn cols [seed]
(let [next #(for [x %] (for [y seed] (str x y)))]
(->> (iterate #(apply concat (next %)) seed)
(mapcat identity))))
(time (first (drop 475254 (cols abc))))
"Elapsed time: 356.879148 msecs"
"AAAAA"
(doc iterate)
-------------------------
clojure.core/iterate
([f x])
Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects
EDIT: Generalization of the function to return the "ordered" subsets of a set
(defn ordered-combinations [seed]
(->> (map list seed)
(iterate #(for [x % y seed] (concat x [y])))
(mapcat identity)))
(def cols
(let [abc (map char (range 65 91))]
(map #(apply str %) (ordered-combinations abc))))
user> (take 30 (map #(apply str %) cols))
("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")
user> (take 28 (ordered-combinations [0 1]))
((0) (1) (0 0) (0 1) (1 0) (1 1) (0 0 0) (0 0 1) (0 1 0) (0 1 1) (1 0 0) (1 0 1) (1 1 0) (1 1 1) (0 0 0 0) (0 0 0 1) (0 0 1 0) (0 0 1 1) (0 1 0 0) (0 1 0 1) (0 1 1 0) (0 1 1 1) (1 0 0 0) (1 0 0 1) (1 0 1 0) (1 0 1 1) (1 1 0 0) (1 1 0 1))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With