现在我正在制作一个应该能够从7(abcdefg)列表中选出3个人的程序,然后将它们分配给犯罪分子。这个“游戏”然后从7个中选出3个随机的peolpe,告诉你这些人中有多少人是犯罪分子,并询问你是否想猜猜这三个罪犯是谁,只猜一猜(“这三个人中有两个是犯罪分子,你想猜猜犯罪分子是谁)。但是,我目前有一个程序可以从列表中抽取3个随机犯罪分子,但是我所拥有的斗争最初是指定谁是罪犯(从列表中随机挑选3个并将其分配给以后可以召回的值)到目前为止,这是我的代码。我希望有人可以指出我正确的方向,我仍然是整个函数式编程的新手。
;allows us to use prompt to ask the user for input
(defun prompt-read (prompt)
(format *query-io* "~a: " prompt)
(force-output *query-io*)
(read-line *query-io*))
;allows you to add elements in needed spots
(defun element-at (org-list pos &optional (ini 1))
(if (eql ini pos)
(car org-list)
(element-at (cdr org-list) pos (+ ini 1))))
(defun element-at (lista n)
(if (= n 1)
(first lista)
(element-at (rest lista) (1- n))))
;allows for the removal of unneeded elements
(defun remove-at (org-list pos &optional (ini 1))
(if (eql pos ini)
(cdr org-list)
(cons (car org-list) (remove-at (cdr org-list) pos (+ ini 1)))))
;returns a chosen number of random elements from a list
(defun rnd-select (org-list num &optional (selected 0))
(if (eql num selected)
nil
(let ((rand-pos (+ (random (length org-list)) 1)))
(cons (element-at org-list rand-pos) (rnd-select (remove-at org-list rand-pos) num (+ selected 1))))))
;returns 3 random criminals from a list of 7
(defun rnd-criminals ()
(rnd-select '(a b c d e f g) 3))
(defun game ()
(prompt-for-players))
;allows for the storing of number of players
(defun num-of-players(number)
(list :number number))
;prompts for the amount of players you want to play
(defun prompt-for-players ()
(num-of-players
(or (parse-integer (prompt-read "How many players are there?"
:junk-allowed t) 0))))
答案 0 :(得分:2)
这是一个没有替换问题的抽样(因为,我认为,你不会想通过每次从列表中挑选同一个人来“挑选三个罪犯”)。有很多方法可以做到这一点。一种方法是生成指数,直到你有足够的不同指数。这样的事情怎么样:
(defun pick (sequence n)
"Return n elements chosen at random from the sequence."
(do ((len (length sequence)) ; the length of the sequence
(indices '()) ; the indices that have been used
(elements '())) ; the elements that have been selected
((zerop n) ; when there are no more elements to select,
elements) ; return the elements that were selectd.
(let ((i (random len))) ; choose an index at random
(unless (member i indices) ; unless it's been used already
(push i indices) ; add it to the list of used indices
(push (elt sequence i) elements) ; and grab the element at the index
(decf n))))) ; and decrement n.
如果你不熟悉do
,你可以使用递归方法,例如,使用本地递归函数:
(defun pick2 (sequence n &aux (len (length sequence)))
(labels ((pick2 (indices elements n)
(if (zerop n) ; if no more elements are needed,
elements ; then return elements.
(let ((i (random len))) ; Otherwise, pick an index i.
;; If it's been used before,
(if (member i indices)
;; then continue on with the same indices,
;; elements, and n.
(pick2 indices elements n)
;; else, continue with it in the list of
;; indices, add the new element to the list of
;; elements, and select one fewer elements
;; (i.e., decrease n).
(pick2 (list* i indices)
(list* (elt sequence i) elements)
(1- n)))))))
;; Start the process off with no indices, no elements, and n.
(pick2 '() '() n)))
另一种方法是基于Efficiently selecting a set of random elements from a linked list,建议Reservoir Sampling。