获得彩票号码

时间:2014-06-08 18:56:02

标签: lisp common-lisp

作为学习Lisp的一部分,我正在尝试编写一个功能,帮助我填写我的彩票。我希望该函数返回

  • 一个清单
  • 中的六个数字,
  • 其中每个数字介于1到49之间,
  • 没有重复的数字,
  • 并以递增的方式排列。

到目前为止,我完成了五项要求中的四项。这是我目前的代码:

(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和一个内部函数,它被递归调用并将列表处理为参数。
  • 从哈希表开始,使用1到49之间的数字作为键,并将键的值设置为nil。然后,在循环内部,获取1到49之间的随机数,并将相应键的值更改为t。返回一次哈希表的六个元素作为值t。恕我直言,这是迄今为止最糟糕的方法,因为它浪费了很多内存并且不能很好地扩展。

您如何看待这些选项,还有其他实现方法吗?高级Lisp开发人员如何解决这个问题?

任何提示?

3 个答案:

答案 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) #'<)))