This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2024-06-29
Channels
- # beginners (16)
- # cider (7)
- # clj-kondo (4)
- # clj-together (1)
- # cljsrn (1)
- # clojure (11)
- # clojure-europe (4)
- # clojure-norway (6)
- # clojure-spec (1)
- # clojurescript (2)
- # datalevin (35)
- # datomic (9)
- # honeysql (1)
- # introduce-yourself (3)
- # lsp (6)
- # off-topic (25)
- # pathom (1)
- # polylith (1)
- # releases (1)
- # shadow-cljs (38)
- # sql (5)
i am building a hexagonal structure made of strings where each cell is named based on the us alphabet e.g. "a, b, c... but then aa, ab, ac, ad.... ba, bb, bc and so on, depending on the number of cells you want to generate. I am used to doing something like this with nested loops, but wondering if there's a better way to construct an arbitrary amount of strings from a collection (the alphabet) in clojure?
If you are working in JVM Clojure, one fun option would be to base something on Integer.toString(..., radix) described at https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#toString-int-int- ...gets you almost all the way there, but would use 0-p, which then you could shift 10 ascii points to a-z
progress so far:
(def alphabet ["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"])
(defn index-to-label [index]
(loop [i (+ 1 index)
acc []]
(if (zero? i)
(apply str (reverse acc))
(recur (quot (dec i) 26)
(conj acc (nth alphabet (mod (dec i) 26)))))))
(defn infinite-labels []
(map index-to-label (range)))
Maybe something like this?
(let [alphabet ["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"]]
(for [x alphabet
y alphabet
:when (not= x y)]
(str x y))) ;; => ("ab" "ac" "ad" "ae" ,,,)
or something like:
(def cell-labels
(let [alphabet (map (comp str char) (range (int \a) (inc (int \z))))
make-longer #(for [seed % next alphabet] (str seed next))]
(apply concat (iterate make-longer alphabet))))
(first cell-labels)
=> "a"
(nth cell-labels 10000)
=> "ntq"
(nth cell-labels 100000)
=> "eqxe"
mega noob question: why does if
need its own scope when used with the fn
syntax, but not when used with the #()
syntax. for example:
(fn [x] (if (= (mod x 2) 0) x nil))
;; vs.
#(if (= (mod % 2) 0) % nil)
how does that explain it?
you are still missing an extra parens
ah yes, here it is: https://cljs.github.io/api/syntax/function
it happens at the code reader level rather than a normal macro. maybe this is what you're looking for? https://clojure.org/reference/reader#_dispatch
it's also possible to use the reader to make the comparison:
(read-string "#(if (= (mod % 2) 0) % nil)")
; => (fn* [p1__1943#] (if (= (mod p1__1943# 2) 0) p1__1943# nil))
; (fn [x] (if (= (mod x 2) 0) x nil)))
it's the same reason for which you can't return vector or map literals in #()
, the form after the #
is embedded in the fn
body as is