beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
oxalorg (Mitesh) 2020-09-19T13:18:24.114900Z

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?

james 2020-09-19T13:29:37.115100Z

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

james 2020-09-19T13:30:44.115300Z

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

jsn 2020-09-19T13:40:12.117Z

I think your solution is fine

jsn 2020-09-19T13:42:02.117200Z

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

βœ”οΈ 1
oxalorg (Mitesh) 2020-09-19T13:44:26.117500Z

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) 2020-09-19T13:45:38.117700Z

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

jsn 2020-09-19T13:46:45.117900Z

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

pithyless 2020-09-19T13:47:51.118300Z

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

πŸ™ 1
oxalorg (Mitesh) 2020-09-19T13:57:56.118500Z

Ah I see! It's wonderful though if you ever get the time to watch. πŸ™‚

2020-09-19T14:05:04.118900Z

a really memory inefficient solution:

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

1
jsn 2020-09-19T14:15:55.119400Z

@caio well, I think its memory requirements are O(1), so I wouldn't call it memory inefficient πŸ™‚

2020-09-19T14:16:54.119600Z

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

2020-09-19T14:17:29.119800Z

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) memory

jsn 2020-09-19T14:18:13.120Z

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

jsn 2020-09-19T14:18:27.120200Z

So it's O(1), I think

2020-09-19T14:19:59.120400Z

hmm. that makes sense

seancorfield 2020-09-19T15:44:50.121200Z

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

πŸ™‚ 1
cp4n 2020-09-19T15:48:36.122300Z

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

sova-soars-the-sora 2020-09-19T16:18:15.122400Z

looks like the perfect use case for memoize

lassemaatta 2020-09-19T16:24:12.122600Z

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.

πŸ‘ 1
lassemaatta 2020-09-19T16:46:13.122800Z

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

sova-soars-the-sora 2020-09-19T17:18:24.123500Z

binary h4x, very l33t.

oxalorg (Mitesh) 2020-09-19T19:05:28.123900Z

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!

Michael W 2020-09-19T20:39:51.125400Z

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

alexmiller 2020-09-19T20:51:35.125600Z

The former

jsn 2020-09-19T21:14:13.127Z

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

Michael W 2020-09-19T21:15:43.127900Z

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

2020-09-19T21:17:12.129Z

you have to wrap it in a fn

jsn 2020-09-19T21:17:15.129300Z

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

Michael W 2020-09-19T21:21:38.130700Z

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.

schmee 2020-09-19T21:22:14.131Z

you can use reader conditionals for that: https://clojure.org/guides/reader_conditionals

schmee 2020-09-19T21:22:21.131200Z

to have one expression for clj and one for cljs

jsn 2020-09-19T21:23:50.131700Z

well, I don't think javascript even has longs

Michael W 2020-09-19T21:25:36.132600Z

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

jsn 2020-09-19T21:26:16.133400Z

I don't think js actually has integers, either πŸ™‚ anyway, js/parseInt should work in clojurescript, I suppose

jsn 2020-09-19T21:28:09.133800Z

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

jsn 2020-09-19T21:29:53.134600Z

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

Michael W 2020-09-19T21:30:53.135500Z

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 W 2020-09-19T21:31:04.135700Z

Thanks again.

Josef Richter 2020-09-19T21:42:25.137300Z

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))]]]))

2020-09-19T21:44:23.137900Z

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.

2020-09-19T21:45:12.138200Z

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

πŸ‘ 1
Josef Richter 2020-09-19T21:46:06.138800Z

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

Josef Richter 2020-09-19T21:48:47.139600Z

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

seancorfield 2020-09-19T21:49:06.139900Z

clojure.java.jdbc/query? Yes.

πŸ‘ 1
seancorfield 2020-09-19T21:49:49.140700Z

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.

πŸ‘ 1
seancorfield 2020-09-19T21:54:01.141900Z

@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.

Josef Richter 2020-09-19T22:07:37.142300Z

thank you @seancorfield