I have updated my Lucky Numbers code:
    (defn indexed-sieve
      "Removes all elements that have a position that is a multiply of
index.
      With first position counting as 1."
      [index this-list]
      (keep-indexed
        (fn [i v]
          (if (= 0 (mod (inc i) index))
              nil
            v))
        this-list))

    ; current-list of Integer instead of default Double makes the code
little more efficient
    ; using reduce would make neater code (no need for atoms),
    ; but gives a stack-overflow for 18.000 and takes about twice as long
    (defn lucky-numbers
      ; doc-string contains max-value
      "Lucky numbers from 1 up-to upto-value.
      1 <= upto-value <= 10.000.000
      http://en.wikipedia.org/wiki/Lucky_number";
      [upto-value]
      ; max-value is also used in doc-string
      (let [max-value (int 1e7)]
        (when (< upto-value 1)
          (throw (Exception. "ERROR: upto-value should at least be 1")))
        (when (> upto-value max-value)
          (throw (Exception. (format "ERROR: upto-value greater then %d"
max-value))))
        (let [current-list    (atom (indexed-sieve 2 (range (int 1) (int
upto-value))))
              current-index   (atom 1)]
          (while (< @current-index (count @current-list))
            (reset! current-list (indexed-sieve (nth @current-list
@current-index) @current-list))
            (reset! current-index (inc @current-index)))
          @current-list)))

Code has become a little bit bigger, but it checks some preconditions now
also.

Is this the good way to document things?

One problem is that max-value is used in the doc-string also, so if it
changes, it has to be done at two places. Is there a way around this?

When running:
    (for [i (range 1 (inc 6))]
      (do
        (time
          (let [upto (int (Math/pow 10 i))]
            (def lucky (lucky-numbers upto))
            (printf "With upto %d there are %d lucky numbers\n" upto (count
lucky))))
          (printf "\n")))

You get on my system:
    (With upto 10 there are 4 lucky numbers
    "Elapsed time: 0.622653 msecs"

    With upto 100 there are 23 lucky numbers
    "Elapsed time: 0.295401 msecs"

    With upto 1000 there are 153 lucky numbers
    "Elapsed time: 5.516305 msecs"

    With upto 10000 there are 1118 lucky numbers
    "Elapsed time: 211.366758 msecs"

    With upto 100000 there are 8772 lucky numbers
    "Elapsed time: 12166.737039 msecs"

    With upto 1000000 there are 71918 lucky numbers
    "Elapsed time: 888851.623386 msecs"

    nil nil nil nil nil nil)

So I think the max-value of 10.000.000 should not be increased. (Maybe
decreased.) If max-value is used I think it will take 15 hours to a day to
compute.


By the way the reduce version that is slower and does not work with a
max-value of 18.000:
    (defn drop-nth [n coll]
      (lazy-seq
        (when-let [s (seq coll)]
          (concat (take (dec n) s) (drop-nth n (drop n s))))))

    (defn lucky-fn
      "Returns sequence of Lucky numbers less than max"
      ([max] (when (pos? max) (lucky-fn 1 (range 1 max 2))))
      ([i acc]
       (if-let [n (nth acc i nil)]
         (recur (inc i) (drop-nth n acc))
         acc)))

If someone knows a way to get a reduce version that gets near the atom
version …

-- 
Cecil Westerhof

-- 
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
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to