As part of learning Lisp I'm currently trying to write a function that helps me fill out my lottery ticket. I want that function to return
- a list
- of six numbers,
- where each number is between 1 and 49,
- without duplicate numbers,
- and being the list ordered in an ascending way.
So far, I'm done with four of the five requirements. This is my current code:
(defun lottery ()
(sort (loop repeat 6 collect (1+ (random 49))) #'<))
When I run this function I get something such as:
(lottery)
;; => (3 10 23 29 41 43)
Basically, everything's fine - except that sometimes I have the very same number twice within the list. And here it starts to get puzzling. My problem is that I'm not too sure on how to solve this in a Lisp way. There are multiple options I can think of:
- Run
remove-duplicates
on the result, then uselength
to check whether the list has less than six elements, and if so, runlottery
a second time,append
it to the first result, usesubseq
to only get the first six elements, and repeat. This works, but is not very elegant, especially as it involves sorting & co. multiple times. - Start with an empty list, create a single random number using
(1+ (random 49))
, and callpushnew
. Now calllottery
recursively with the list untillength
returns six. I like this approach way more, but I'm still not too convinced, as this way I'd need two functions: An outer one,lottery
, and an inner one, that is called recursively and handles the list as parameter. - Start with a hash-table, use the numbers from 1 to 49 as keys, and set the keys' value to
nil
. Then, inside a loop, get a random number between 1 and 49, and change the value of the appropriate key tot
. Return once six elements of the hash-table havet
as value. IMHO this is the worst approach so far, as it wastes memory quite a lot and doesn't scale well.
What do you think of those options, and are there other ways of implementing this? How would an advanced Lisp developer solve this?
Any hints?