On Thu, Feb 17, 2011 at 1:39 AM, Shantanu Kumar
<kumar.shant...@gmail.com> wrote:
> On Feb 17, 11:09 am, Ken Wesson <kwess...@gmail.com> wrote:
>> On Thu, Feb 17, 2011 at 12:29 AM, Andreas Kostler
>>
>> <andreas.koestler.le...@gmail.com> wrote:
>> > Is there an easy and idiomatic way of getting the digits of a number in 
>> > clojure?
>>
>> > (defn explode-to-digits [number]
>> >        (map #(- (int %) (int \0)) (str number)))
>> > (explode-to-digits 123456)
>> > => (1 2 3 4 5 6)
>>
>> > Seems a bit clunky...
>>
>> How about
>>
>> (defn explode-to-digits [n]
>>   (if (= n 0)
>>     []
>>     (let [d (rem n 10)
>>           r (quot n 10)]
>>       (conj (explode-to-digits r) d))))
>>
>> or if you want to avoid consuming stack
>>
>> (defn explode-to-digits* [n out]
>>   (if (= n 0)
>>     out
>>     (let [d (rem n 10)
>>           r (quot n 10)]
>>       (recur r (cons d out)))))
>>
>> (defn explode-to-digits [n]
>>   (explode-to-digits* n nil))
>>
>> It should also be possible to make a lazy sequence version, but
>> returning the digits in the reverse order.
>
> A bit shorter:
>
> (defn digits [n]
>  (let [r (rem n 10)
>        q (int (/ n 10))
>        _ (println (format "q=%d, r=%d" q r))]
>    (if (zero? q) [r]
>      (into [r] (digits q)))))
>
> Not efficient though.

If you really want efficient:

(defn digits [n]
  (loop [n (int n)
         out nil]
    (if (zero? n)
      out
      (recur
        (unchecked-divide n 10)
        (cons
          (unchecked-remainder n 10)
          out)))))

If you really /really/ want efficient:

(defn digits [n dig-max]
  (let [a (int-array dig-max)]
    (loop [n (int n) i (int (dec dig-max))]
      (when-not (zero? n)
        (aset a i (unchecked-remainder n 10))
        (recur
          (unchecked-divide n 10)
          (unchecked-dec i))))
    (seq a)))

Icky but should be fastest possible in Clojure. This one will throw an
exception if dig-max is too small and produce leading zeros if it's
bigger than the number of digits of n, and it will truncate inputs
that don't fit in a 32-bit signed int. You can wrap in (drop-while
zero? ...) to lose the latter behavior but it will slow things down,
or use Math/log10 and slow things down even more.

All of the variations I've posted will turn negative numbers into seqs
of digits that are all negated, e.g. (-1 0 -2 -4 -5 -6) and are liable
to hang, blow the heap (pretty slowly), or blow the stack (variously)
on fractions of any kind (Ratios, doubles, etc.).

In practice, if I needed something like this in production code, I'd
probably use one of the nicely idiomatic versions from earlier --
after all, the complexity is logarithmic in the magnitudes of the
numbers you're using anyway -- and handle negative and fractional
inputs in some more elegant manner. I'd probably also generalize it to
accept an arbitrary radix as an optional second parameter. This would
simply replace all the literal 10s in the code. It too would need to
be sanity checked, for being an integer and >= 2.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to