Fork me on GitHub
Sara Wänerskär06:10:58

Hi! I am working on, where I am supposed to calculate interest rate using BigDecimal. I am not able to get some of the tests to pass. There must be something that I am missing about multiplication and percentage with BigDecimal. Any help would be greatly appreciated! SRC

(defn interest-rate
  "Get interest rate for balance"
  (cond (< balance 0) -3.213
        (< balance 1000) 0.5
        (< balance 5000) 1.621
        :else 2.475)

(defn annual-balance-update
  "Calculate balance update"
  (bigdec (* balance (+ (* (interest-rate balance) 0.01) 1)))
TEST Test 1
(deftest annual-balance-update-large-positive-balance-test
  (is (= 1016.210101621M (interest-is-interesting/annual-balance-update 1000.0001M))))
Result 1 Assertion failed: Expected :920352587.26744292868451875M Actual :920352587.267443M Test 2 (deftest annual-balance-update-small-negative-balance-test (is (= -0.12695199M (interest-is-interesting/annual-balance-update -0.123M)))) Result 2 Assertion failed: Expected :-0.12695199M Actual :-0.11904801M

Tarasov Oleg07:10:27

(defn annual-balance-update   "Calculate balance update"   [balance]   ( balance (+ (bigdec ( (interest-rate balance) 0.01)) 1)))

Lennart Buit09:10:28

you can use triple-backtick to get a multiline code fragment in slack 🙂

Hello, World!

👍 1
Sara Wänerskär09:10:17

Thank you Lennart, I edited my post according to your suggestion to make it easier to read.

👍 1
Jonathan Chen17:10:36

Just for my understanding, the fix was to convert to bigdec earlier in the process so precision isn't lost?

Redbeardy McGee10:10:22

I have a map of maps. I need the inner map where the value of a particular key matches a given string. Perhaps naively, I started with (filter #(= "string" (:key %)) map-of-maps). This does extract the correct map, but the result is a lazy seq now so I cannot use normal hashmap fns to work with the data contained within. As a workaround, I just used (into {} inner-map) to get a hashmap back instead. It works, but it feels like I've gone roundabout by having the intermediate lazy seq.


Can you give an example of what map-of-maps looks like?

Redbeardy McGee10:10:56

{:k1 foo :k2 bar, :k3 {:inner-k1 foo, :inner-k2 "correct map", :inner-k3 bar}, :k4 quux, :k5 {:inner-k1 foo, :inner-k2 "wrong map", :inner-k3 bar}}

Redbeardy McGee10:10:12

oh that did not let me fix the formatting

Redbeardy McGee10:10:05

The outer map has some irrelevant key-value pairs. There is 1 singular inner map which is important, but is only denoted by the "important value" inside the map.


There are two inner maps with "important value" there?

Redbeardy McGee10:10:51

i only want 1 of the inner maps.

Redbeardy McGee10:10:07

the other inner maps will not have the same value at :inner-k2


So you want one inner map whose :inner-k2 equals "important value"?


Right, I was just about to say that your example input doesn't really match with what you're saying. 🙂

Redbeardy McGee10:10:24

in that example, i need to extract :k3 's value, where :inner-k2 is "correct map"

Redbeardy McGee10:10:49

In another case, i may need the map at :k5 instead, but that's another day


If you just want to avoid the intermediate lazy seq, you can use the transducer arity of into:

user=> (def map-of-maps
         {:k1 {}
          :k2 {}
          :k3 {:inner-k1 "foo" :inner-k2 "correct map" :inner-k3 "bar"}
          :k4 {}
          :k5 {:inner-k1 "foo" :inner-k2 "wrong map" :inner-k3 "bar"}})
user=> (into {}
         (filter (comp #{"correct map"} :inner-k2 val))
{:k3 {:inner-k1 "foo", :inner-k2 "correct map", :inner-k3 "bar"}}
However, whenever I find myself doing linear search, I start thinking about whether I should maybe restructure my data instead. One option is to index the input first and then look up the value by the index:
user=> (into {}
         (map (juxt (comp :inner-k2 val) identity))
{nil [:k4 {}],
 "correct map" [:k3 {:inner-k1 "foo", :inner-k2 "correct map", :inner-k3 "bar"}],
 "wrong map" [:k5 {:inner-k1 "foo", :inner-k2 "wrong map", :inner-k3 "bar"}]}
user=> (peek (get *1 "correct map"))
{:inner-k1 "foo", :inner-k2 "correct map", :inner-k3 "bar"}

Redbeardy McGee11:10:43

I'm not sure what approach to take. Something about producing an intermediate sequence seemed incorrect because I just need the single inner map with the correct key-value pair, and then will be using some of the values in that map.


Filtering a map does produce a sequence, but it is lazy, so it only computes as much as is needed. Putting something like

(->> (vals m)
     (filter (comp #{"correct map"} :inner-k2))
in a function so you can parametrize the key and value to match against. This is functionally equivalent to a loop that stops as soon as it finds the correct map.

Redbeardy McGee11:10:49

so I shouldn't be concerned with the intermediate sequence, and just take more care to recognize when one will be generated

Redbeardy McGee11:10:11

Thanks to both of you for clarifying some of these things for me!


Ideally you don't want to traverse data. Better than searching your data is querying it. But when restructuring like in the second example of @U4ZDX466T is impractical or has too much overhead, yes you shouldn't have to worry about intermediate lazy sequences.

Redbeardy McGee11:10:54

I don't want to be doing this, but I received it from an API in this outlandish format


Then you can consider whether normalizing it in some way up front makes sense for further processing

Redbeardy McGee11:10:42

And that would be like the example above, finding the kv i'm after and then turning that value into a key of a new map?


Creating an index like that would be an example, yes


I wanted to get an id list according to a numeric string, I believe I'm doing the wrong map, do not know how to proceed, can someone help me


user> (distinct (map {\1 "a" \2 "a" \3 "b" \4 "b"} "1234"))
("a" "b")


Mapping over the input string like above is a nice way to go about it. A substitution map ch->opt can be built up like

(let [id-list [{:id "b" :option [2 4]} {:id "a" :option [1 3]}]
      ch->opt   (into {}
                      (map (fn [{:keys [id option]}]
                             (zipmap (map #(Character/forDigit % 10) option) (repeat id))))
  (distinct (map ch->opt "1234")))


You might also prefer

(let [id-list   [{:id "b" :option [2 4]} {:id "a" :option [1 3]}]
      ch->opt   (into {} (map (fn [{:keys [id option]}] (zipmap option (repeat id)))) id-list)]
  (distinct (map ch->opt (map #(Integer/parseInt %) (str/split "1234" #"")))))


distinct of course not dedupe. i edit mine.


Does anybody know good resources for Clojure live coding? I am still having trouble adapting to the Clojure way of programming and it would be nice if I could see someone implement a solution to a problem while hearing their thoughts going into the implementation? Any books, blogs, etc that can help in this regard are also highly appreciated


I did a pretty long live coding demo for London Clojurians a while back and their are a few shorter ones on my YouTube channel


I think there's some videos linked from the Practicalli site as well. There are probably quite a few other videos out there from individuals.

❤️ 1

I watched the above video and can recommend it! This is one Iquite enjoyed too:


Oh and I think there is a very friendly tutorial like channel that someone recommended recently: “on the code again”


The 4Clojure walkthrough videos are examples of thinking through code decisions, most challenges have several approaches to solving the problem


Thank you all very much 🙌

Rob Haisfield22:10:22

Anyone know of a good Web3 library? I couldn’t find anything recent. I saw this but it hasn’t been updated in a while so idk if it still works.