Fork me on GitHub
oxalorg (Mitesh)13:09:24

Hi everyone. I want to know what would be the idiomatic way to do something like this in clojure: To find the first power (exponent) of 2 which is greater than a give number. (So for 10 it is 2^4, for 5 it is 2^3) In python my first instinct would be to do something like this:

def find_closest_exponent(num, base=2):
    power = 0
    while num > 1:
        num = num / base
        power += 1
    return power
In clojure my first instinct was something like this:
(defn find-closest-exponent [num base] 
  (loop [power 0 acc num] 
    (if (< acc 1) power 
      (recur (inc power) (/ acc base)))))
This is good enough and it works, I'm just trying to expand my thinking if there are other ways you would use to solve something like this?


Off-topic: You can do this with the bit_length method in Python.


(Sorry, don't know if there's an equivalent in Clojure, but Common Lisp has it, so not impossible, I guess.)


I think your solution is fine


I would probably grow acc from 1 and compare it to num instead, but that's just my personal taste, perhaps

✔️ 3
oxalorg (Mitesh)13:09:26

Thanks I tried porting the python code as-is using (while) in clojure, but that meant I had to mutate the variables which didn't feel right

oxalorg (Mitesh)13:09:38

(also off topic, we both have a Rurourni Kenshin profile picture haha)


huh! 🙂 yeah, but I didn't even watch it, I think (even though I have this avatar pic for like 20 years or something)

oxalorg (Mitesh)13:09:56

Ah I see! It's wonderful though if you ever get the time to watch. 🙂


a really memory inefficient solution:

(defn closest-exponent [num base]
  (->> (iterate #(/ % base) num)
       (take-while #(> % 1))


@U0GRKUGLQ well, I think its memory requirements are O(1), so I wouldn't call it memory inefficient 🙂


it's actually O(logbase(num)) since using take-while will keep the sequence in-memory before counting


extracting this counting logic:

(defn count-while [pred coll]
  (or (->> (map-indexed list coll)
           (drop-while #(pred (second %)))
      (count coll)))

(defn closest-exponent [num base]
  (->> (iterate #(/ % base) num)
       (count-while #(> % 1))))
this would be o(1) memory


I don't think so, there's no reason for take-while not to return a lazy-seq , and count doesn't keep head


So it's O(1), I think


hmm. that makes sense


looks like the perfect use case for memoize


if you're willing to do a bit of java interop and bit shifting, then the Long and Integer classes have some methods (e.g. highestOneBit) which might allow you to do this in constant time 🙂 I don't have a repl handy so I can't check whether that function does what I think it does.

👍 3

perhaps (fn [i] (* 2 (Long/highestOneBit i))) is enough


binary h4x, very l33t.

oxalorg (Mitesh)19:09:28

Thanks everyone! Thanks caio, although I did not understand what was happening with your code at first, after hours of and giving it some thought now it looks straightforward and wonderful!


Hi folks When i want to add this block to ns i get following error. Can u figure out whats happening here?

(ns something
    (java.util.concurrent Executors))) 
Syntax error macroexpanding clojure.core/ns at (core.clj:1:1).
() - failed: Insufficient input at: [:ns-clauses :import :classes :package-list :classes] spec: :clojure.core.specs.alpha/package-list
(java.util.concurrent.Callable) - failed: simple-symbol? at: [:ns-clauses :import :classes :class] spec: :clojure.core.specs.alpha/import-list
:import - failed: #{:refer-clojure} at: [:ns-clauses :refer-clojure :clause] spec: :clojure.core.specs.alpha/ns-refer-clojure
:import - failed: #{:require} at: [:ns-clauses :require :clause] spec: :clojure.core.specs.alpha/ns-require
:import - failed: #{:use} at: [:ns-clauses :use :clause] spec: :clojure.core.specs.alpha/ns-use
:import - failed: #{:refer} at: [:ns-clauses :refer :clause] spec: :clojure.core.specs.alpha/ns-refer
:import - failed: #{:load} at: [:ns-clauses :load :clause] spec: :clojure.core.specs.alpha/ns-load
:import - failed: #{:gen-class} at: [:ns-clauses :gen-class :clause] spec: :clojure.core.specs.alpha/ns-gen-class


(:import (java.util.concurrent Callable ExecutorService Executors))

🙏 3

Welcome @cp4n! Saw your post on Reddit about learning Clojure!

🙂 3

Thanks @seancorfield, really excited to learn it. There was a lot of useful advice in the responses!

Michael W20:09:51

Is it better to use (Long/parseLong "10")or (long (bigdec "10")) to coerce a string to a long?


is there a reason why there's a bigdec constructor taking a string but there is no long constructor taking a string?

Michael W21:09:43

I can't seem to use Long/parseLong as a function in an update: (update {:a 1 :b "2"} :b Long/parseLong) this fails: Unable to find static field: parseLong in class java.lang.Long


you have to wrap it in a fn


@michael819 it's because it's not quite a function, it's a static java method; try using #(Long/parseLong %) instead?

Michael W21:09:38

Hmmm it's not compatible with cljs either so it causes a build warning... Need to figure something out that will work for both. Thanks for the help, it's working in clj but not cljs.


you can use reader conditionals for that:


to have one expression for clj and one for cljs


well, I don't think javascript even has longs

Michael W21:09:36

I guess I need an integer not a long, but same thing, works in Java, not in JS


I don't think js actually has integers, either 🙂 anyway, js/parseInt should work in clojurescript, I suppose


#(#?(:clj Long/parseLong :cljs js/parseInt) %) works in my tests


(man, I have serious problems with my cut-n-paste skills :/)

Michael W21:09:53

Yeah that removed the build warnings, I don't even think my code will get ran in cljs, it's a resolver for fulcro, but rather not have the warnings.

Michael W21:09:04

Thanks again.

Josef Richter21:09:25

hi, I have this simple hiccup page that receives a map correctly, but for some reason accessing keys of that map returns nil - can anybody please tell me why? I expect this to be some obvious noob mistake… see FIXME below:

  (:require [ :refer [html5]]
            [hiccup.core :refer [html h]]))

(defn item-page [item]
  (println item) ;; => ({:id #uuid "84a8c493-717d-41be-ba3d-52805b495524", :name one, :description one, :checked false, :date_created #inst "2020-09-18T11:32:18.416622000-00:00"})
  (println (:name item)) ;; => nil FIXME why is this nil?
  (html5 {:lang :en}
          [:meta {:name :viewport
                  :content "width=device-width, initial-scale=1.0"}]
          [:link {:href "/bootstrap/css/bootstrap.min.css"
                  :rel :stylesheet}]]
           [:h2 "Item detail"]
            (h (:name item))]
            (h (:description item))]]]))


The output from (printn item) that you show has parens around it, so it is probably either a list or some other kind of sequence of maps, not just a map.


user=> (def x1 '({:a 1 :b 2}))
user=> (:a x1)
user=> (def m1 '{:a 1 :b 2})
user=> (:a m1)
user=> (:a (first x1))

👍 3
Josef Richter21:09:06

bingo!! I’m getting a list with a single map in it. understood, thank you!

Josef Richter21:09:47

ok fixed. maybe the question that comes to my mind - does jdbc/query always return a list?

seancorfield21:09:06 Yes.

👍 3

get-by-id returns a single hash map (representing a single row). query and find-by-keys return a "result set": a sequence of hash maps.

👍 3

@josef.richter If you have questions about (or it's replacement, next.jdbc), the #sql channel is a good place to get detailed answered (and I'm more likely to see questions there because it's lower traffic.