Rcjp's Weblog

December 26, 2006

lotto numbers

Filed under: lisp, python — rcjp @ 9:26 am

I can’t remember how I came to be subscribed to a perl feed but I ended up reading http://www.oreillynet.com/onlamp/blog/2006/12/99_problems_in_perl_6.html
which was based on something similar in Lisp I think. The article showed some Scheme like Common Lisp solution to picking out the lottery numbers all cons’s etc.

My first somewhat crumby solution was

    (defun lotto (n m)
      "Draw N different random numbers from the set 1..M"
      (loop for num = (1+ (random m))
         for bag = nil then (adjoin num bag)
         while (< (length bag) n)
         finally (return bag)))

as I first thought of the adjoin function when I thought about adding numbers, but you shouldn’t be adjoining and then setting the result back to itself – pushnew would do that. Maybe its clearer just to use member

    (defun lotto1 (n m)
      (loop while (< (length bag) n)
         for num = (1+ (random m))
         unless (member num bag) collect num into bag
         finally (return bag)))

I vaguely remembered a thread on comp.lang.lisp on this subject and found a post from Alan Crowe did it prettier with ‘do’ – slapped wrists for me since I always dismiss ‘do’ as being harder to read than loop

    (defun lotto2 (n m)
      (do ((draw '()))
          ((= (length draw) n) draw)
        (pushnew (+ (random m) 1) draw)))

Of course these don’t work well if you want 49 out of 50 as there are too many non-unique numbers generated, Brian Downing posted a version using a nice idea of generating a list of numbers with an associated random number and sorting on that random number to shuffle the list

    (defun lotto3 (n m)
      (subseq (mapcar #'car (sort (loop for i from 1 upto m
                                     collect (cons i (random 1.0)))
                                  #'< :key #'cdr))
              0 n))

In python, as I was looking up the random function, the docs showed how you can do this sort of thing in one line (remember xrange, like range, generates numbers upto but not including the second arg)

    In [16]: random.sample(xrange(1,50),6)
    Out[16]: [29, 28, 32, 45, 42, 2]


Leave a Comment »

No comments yet.

RSS feed for comments on this post.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: