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
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
(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)
(:import (java.util.concurrent Callable ExecutorService Executors))
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))
count))
@caio 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 %)))
ffirst)
(count coll)))
(defn closest-exponent [num base]
(->> (iterate #(/ % base) num)
(count-while #(> % 1))))
this would be o(1)
memoryI 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
Welcome @cp4n! Saw your post on Reddit about learning Clojure!
Thanks @seancorfield, really excited to learn it. There was a lot of useful advice in the responses!
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.
perhaps (fn [i] (* 2 (Long/highestOneBit i)))
is enough
binary h4x, very l33t.
Thanks everyone! Thanks caio, although I did not understand what was happening with your code at first, after hours of http://clojuredocs.org and giving it some thought now it looks straightforward and wonderful!
Is it better to use (Long/parseLong "10")
or (long (bigdec "10"))
to coerce a string to a long?
The former
is there a reason why there's a bigdec
constructor taking a string but there is no long
constructor taking a string?
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?
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: https://clojure.org/guides/reader_conditionals
to have one expression for clj and one for cljs
well, I don't think javascript even has longs
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 :/)
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.
Thanks again.
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:
(ns webdev.item.show
(:require [hiccup.page :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}
[:head
[:meta {:name :viewport
:content "width=device-width, initial-scale=1.0"}]
[:link {:href "/bootstrap/css/bootstrap.min.css"
:rel :stylesheet}]]
[:body
[:div.container
[:h2 "Item detail"]
[:div.row
(h (:name item))]
[:div.row
(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/x1
user=> (:a x1)
nil
user=> (def m1 '{:a 1 :b 2})
#'user/m1
user=> (:a m1)
1
user=> (:a (first x1))
1
bingo!! Iβm getting a list with a single map in it. understood, thank you!
ok fixed. maybe the question that comes to my mind - does jdbc/query always return a list?
clojure.java.jdbc/query
? Yes.
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.
@josef.richter If you have questions about clojure.java.jdbc
(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.
thank you @seancorfield