【问题标题】:Get numbers for the lottery获取彩票号码
【发布时间】:2014-07-29 08:50:37
【问题描述】:

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

  • 列表
  • 六个数字,
  • 其中每个数字都在 1 到 49 之间,
  • 没有重复的数字,
  • 并且是按升序排列的列表。

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

(defun lottery ()
  (sort (loop repeat 6 collect (1+ (random 49))) #'<))

当我运行这个函数时,我会得到如下信息:

(lottery)
;; => (3 10 23 29 41 43)

基本上,一切都很好 - 除了有时我在列表中有两次相同的数字。在这里它开始变得令人费解。我的问题是我不太确定如何以 Lisp 方式解决这个问题。我能想到多种选择:

  • 在结果上运行remove-duplicates,然后使用length检查列表是否少于六个元素,如果是,第二次运行lotteryappend它到第一个结果,使用@ 987654327@只获取前六个元素,然后重复。这行得通,但不是很优雅,尤其是当它涉及排序和合作时。多次。
  • 从一个空列表开始,使用(1+ (random 49)) 创建一个随机数,然后调用pushnew。现在用列表递归调用lottery,直到length 返回6。我更喜欢这种方法,但我仍然不太相信,因为这样我需要两个函数:一个外部函数 lottery 和一个内部函数,它被递归调用并将列表作为参数处理。
  • 从哈希表开始,使用从 1 到 49 的数字作为键,并将键的值设置为 nil。然后,在一个循环中,获取一个 1 到 49 之间的随机数,并将相应键的值更改为 t。一旦哈希表的六个元素具有t 作为值,则返回。恕我直言,这是迄今为止最糟糕的方法,因为它非常浪费内存并且不能很好地扩展。

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

有什么提示吗?

【问题讨论】:

    标签: lisp common-lisp


    【解决方案1】:

    创建一个从 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)
    

    【讨论】:

    • 有时你只见树木不见森林。谢谢:-)!
    • 请注意,使用向量会更有效。
    • 抱歉,我觉得这个随机播放不合适。切换两个随机元素 length 次会在原来的位置留下太多元素。循环应该类似于(loop :for i :downfrom (1- (length list)) :downto 1 :do (rotatef (nth i list) (nth (random i) list)))
    • @Golo,On Lisp 在 Paul Graham 的 personal site 上可用。或者我猜你喜欢阅读好的旧纸质书?无论如何,这本书很棒。
    • @GoloRoden 在 Svante 的评论中应该是 (random (+ i 1)) 而不是 (random i) - 因为它会在原来的位置留下太少的元素。
    【解决方案2】:
    (defun lotto ()
      (labels ((lot (acc)  
                 (if (= 6 (length acc)) 
                     acc 
                    (lot (adjoin (1+ (random 49)) acc)))))
        (sort (lot nil) #'<)))
    

    【讨论】:

    • 添加一些解释/cmets/...怎么样?
    【解决方案3】:

    使用由递归提供的累加器:

    (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 本地函数。此函数在接口内提供的列表中获取一个随机数,并在列表中调用自身减去所选元素。最后一步是对结果列表进行排序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-04
      • 2019-12-24
      • 2016-02-04
      • 1970-01-01
      • 1970-01-01
      • 2019-03-27
      相关资源
      最近更新 更多