2
\$\begingroup\$

Doing a challenge to print the number that you would get if you convert a given number to binary, invert its bits, then convert back to decimal.

I decided to give it a run in clojurescript (which I don't really know) and while all the below makes sense to me, it has to be possible to do it better and without dropping to js functions as often as I felt I had to.

(def invert-number [n] (+ 1 (* -1 n)))
(defn number-complement [num]
 (let [numstr (.toString num 2)
       bits (map (comp invert-number js/parseInt) numstr)
       complement-bits (reduce str bits)]
      js/parseInt complement-bits 2)))
\$\endgroup\$
1
  • \$\begingroup\$ yes sorry, not sure how the copy paste came out wrong...the first should have been a defn .... maybe I copied an older version from the console? I'll fix it up \$\endgroup\$ Commented Aug 13, 2019 at 21:21

1 Answer 1

1
\$\begingroup\$

First, fixing a few of the errors that I noted in the comments and altering the formatting a bit, I have:

(defn invert-number [n]
  (+ 1 (* -1 n)))

(defn number-complement [num]
 (let [numstr (.toString num 2)
       bits (map (comp invert-number js/parseInt) numstr)
       complement-bits (reduce str bits)]

   (js/parseInt complement-bits 2)))

(println (number-complement 10)
         (number-complement 12)
         (number-complement 15)
         (number-complement 993061001)
         (number-complement 123))

; 5 3 0 80680822 4

I prefer to have defn function definitions on a separate line, and have at least one empty line between function definitions.


invert-number can be fixed up a bit. - can actually be used as an unary operator to do a negation, and inc is arguably more idiomatic than + 1 unless you think you may need to add to the equation later. I changed it to:

(defn invert-number2 [n]
  (inc (- n)))

Since the entire purpose of the function though seems to be just toggling between 0 and 1, I'd just write it as a more explicit toggle:

(defn invert-number2 [n]
  (if (zero? n) 1 0))

I feel like that conveys the purpose much clearer. I'd expect it to perform similarly too.


You can get rid of the first call to js/parseInt by just using int:

(map (comp invert-number2 int) numstr)

Honestly, I don't know why this works. int here is not acting like it does in Clojure (which is what I'm familiar with; I don't actually know Cljs). I'm guessing this is due to some weirdness on Javascript's end. If I plug that into a Cljs transpiler, I get some weird clues:

(int "192837465")

becomes

("192837465" | (0));

Because... Javascript happened?

The second js/parseInt is a little harder to deal with though because of the radix argument. I'd just stick with what you have.


(reduce str bits) can be changed to (apply str bits). Many variadic functions automatically manually reduce over their arguments (like str and +), so you you can alternatively apply the list directly to the function. (apply str makes a little more sense to me, but that's likely because I've written that many times before.


In the end, I ended up with:

(defn invert-number2 [n]
  (if (zero? n) 1 0))

(defn number-complement2 [num]
 (let [numstr (.toString num 2)
       bits (map (comp invert-number2 int) numstr)

       complement-bits (apply str bits)]

   (js/parseInt complement-bits 2)))

(println (number-complement2 10)
         (number-complement2 12)
         (number-complement2 15)
         (number-complement2 993061001)
         (number-complement2 123))

; 5 3 0 80680822 4
\$\endgroup\$
1
  • \$\begingroup\$ great tip on applying here. Oh and of course my variable names kinda suck - I'll own that \$\endgroup\$ Commented Aug 14, 2019 at 3:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.