As an ArgoUML contributor I'm going to blog my activities here, so that they may draw interest by other developers or help other developers when doing tasks similar to what I've done. AND(!) the grand vision that makes an Argonaut what he is, TO THRIVE IN THE BIG DANGEROUS WORLD, TAKING THE Argo TO A GOOD SHORE ;-))

Wednesday, October 27, 2010

Programming Praxis Alien Numbers in Clojure

I solved the full Programming Praxis Alien Numbers exercise in Clojure. This enabled me to learn more about Clojure and to train my algorithmic parts of the brain a bit.

In all this I was a bit disappointed. It took me too much time to reach a full solution and then, in the core part of the exercise I had to resort to one of the other persons to reach a better way to convert a decimal number to an arbitrary radix number given its language.

I was also a bit disappointed in the way that I wasn't able to use Clojure's laziness more in the algorithms, resorting too much for my taste to loop. From a positive point of view, the Clojure abstractions work as advertised and the only difference from the code bellow and another that would use instead of strings a vectors or lists would be the conversion in the return value of decimal-to-lang.

Follows the core of the exercise solution. Note that the full solution with tests is here. Still considering the Clojure sweet points, I think I could easily explore its excellent support for concurrency and convert the main algorithm into a parallel one if there were hundreds of lines to be processed.

(defn decimal-to-lang
  "Converts decimal-num to the equivalent number in lang as a string.
  The algorithm was a translation of the algorithm by Rodrigo Menezes
  in C# that he posted in the programming praxis site."
  [decimal-num lang]
  (let [lang-radix (count lang)]
    (loop [decimal-value decimal-num lang-num []]
      (if (>= 0 decimal-value)
 (apply str lang-num)
 (recur (int (/ decimal-value lang-radix))
        (concat [(nth lang (mod decimal-value lang-radix))] lang-num))))))

(defn digit-index
  [digit lang]
  (loop [i 0]
    (if (= digit (nth lang i))
      i
      (recur (inc i)))))

(defn lang-to-decimal
  [alien-num lang]
  (let [radix (count lang)
 ralien-num (reverse alien-num)]
    (loop [i 0 decimal-num 0 product 1]
      (if (= i (count ralien-num))
 decimal-num
 (recur (inc i) (+ decimal-num (* (digit-index (nth ralien-num i) lang) product))
        (* radix product))))))

(defn convert-num
  "Convert alien-num which is in source-lang into the same number in target-lang"
  [alien-num source-lang target-lang]
  (decimal-to-lang (lang-to-decimal alien-num source-lang) target-lang))

2 comments:

Javier said...

Hi! inspired by your post i try to implement a soltution from a different approach: generating de data structures fitted to seq manipulation. First generating a lazy infinite seq of numbers of each lang, indexing first seq and get the index of the alien number param to get the number in the list of numbers of second lang.
The cod is here: https://gist.github.com/672192

euluis said...

Thanks for the link. I'm trying to understand it, but, it isn't getting into my head right now. Maybe that is the thing, I've yet to understand laziness. I think studying your resolution might help.

Reader Shared items

Followers