作为学习Lisp的一部分,我正在尝试编写一个功能,帮助我填写我的彩票。我希望该函数返回
到目前为止,我完成了五项要求中的四项。这是我目前的代码:
(defun lottery ()
(sort (loop repeat 6 collect (1+ (random 49))) #'<))
当我运行此功能时,我得到的内容如下:
(lottery)
;; => (3 10 23 29 41 43)
基本上,一切都很好 - 除了有时我在列表中有两次相同的数字。在这里它开始变得令人费解。我的问题是我不太确定如何以Lisp方式解决这个问题。我能想到多种选择:
remove-duplicates
,然后使用length
检查列表是否少于六个元素,如果是,请再次运行lottery
append
它是第一个结果,使用subseq
只获得前六个元素,然后重复。这可行,但不是很优雅,特别是因为它涉及排序和合。多次。(1+ (random 49))
创建一个随机数,然后调用pushnew
。现在用列表递归调用lottery
,直到length
返回6。我更喜欢这种方法,但我仍然不太相信,因为这样我需要两个函数:一个外部函数lottery
和一个内部函数,它被递归调用并将列表处理为参数。nil
。然后,在循环内部,获取1到49之间的随机数,并将相应键的值更改为t
。返回一次哈希表的六个元素作为值t
。恕我直言,这是迄今为止最糟糕的方法,因为它浪费了很多内存并且不能很好地扩展。您如何看待这些选项,还有其他实现方法吗?高级Lisp开发人员如何解决这个问题?
任何提示?
答案 0 :(得分:4)
创建一个从1到49的所有数字的列表,随机播放,取6,排序。
=> (sort (take 6 (shuffle (range 1 50))))
; (8 14 16 23 34 39)
为了展示最终的实施,我在这里添加:
(defun shuffle (list)
(let ((len (length list)))
(loop repeat len
do
(rotatef
(nth (random len) list)
(nth (random len) list))
finally
(return list))))
(defun lottery ()
(sort (subseq (shuffle (loop for i from 1 to 49 collect i)) 0 6) #'<))
(lottery)
;; => (5 6 17 21 35 37)
答案 1 :(得分:0)
使用递归提供的累加器:
(defun lottery ()
(setf grid (loop for i from 1 to 49 collect i))
(labels ((choose (source num)
(if (or (null source) (zerop num))
nil
(let ((elem (nth (random (length source)) source)))
(cons elem (choose (remove elem source) (1- num)))))))
(sort (choose grid 6) #'<)))
彩票功能首先生成放入grid
变量的数字列表。然后我们定义一个内部choose
本地函数。此函数在接口内提供的列表中获取一个随机数,并在列表中调用自身减去所选元素。最后一步是对结果列表进行排序。
答案 2 :(得分:0)
(defun lotto ()
(labels ((lot (acc)
(if (= 6 (length acc))
acc
(lot (adjoin (1+ (random 49)) acc)))))
(sort (lot nil) #'<)))