首先,一些重新格式化:
(loop for e in entries do
(if (and (not (member e sub))
(not (member e col)))
(progn (setq choices (nconc choices (list e)))
(print choices)))
(if (= (length choices) 1)
(setq pick (car choices))
(if (not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
然后,如果您不需要 的替代子句if
,但想要 a progn
,则可以使用when
:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(if (= (length choices) 1)
(setq pick (car choices))
(if (not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
最后两个if
子句是互斥的,所以要么 要么cond
合适case
(我cond
现在将使用):
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (= (length choices) 0))
(setq pick (nth (random (+ 0 (length choices))) choices))))
有一个zerop
谓词:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (+ 0 (length choices))) choices))))
我看不出将 0 添加到某个值应该完成什么:
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices))))
除非您确定pick
一开始就设置为合理的默认值,否则您可能应该有一个默认情况(这可能是您的问题之一):
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(setq choices (nconc choices (list e)))
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil))
您可以使用而不是使用setq
and (这会将新元素放在列表的开头,但是由于您无论如何都是随机选择的,因此不必担心):nconc
push
(loop for e in entries do
(when (and (not (member e sub))
(not (member e col)))
(push e choices)
(print choices))
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil))
我怀疑在这个片段的开头,choices
应该是()
,在这个片段之后你不需要choices
,并且打印choices
只是为了调试,所以你可以通过使用remove-if
和更改条件以不同的方式做到这一点:
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(cond ((= (length choices) 1)
(setq pick (car choices)))
((not (zerop (length choices)))
(setq pick (nth (random (length choices)) choices)))
(t
(setq pick nil)))
如果choices
按现在打印()
,则意味着此处没有选择,因此您必须在那时进行一些回溯(或者当到达死胡同时,您的算法会执行任何操作)。
最后,由于(length choices)
只能是非负整数,如果您以不同的顺序测试案例,您可以使用case
而不是:cond
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(case (length choices)
(0 (setq pick nil))
(1 (setq pick (car choices)))
(otherwise (setq pick (nth (random (length choices)) choices)))))
按要求更新。
正如 Rainer 指出的,这基本上是一个pick
函数的主体,所以我们可以去掉所有的自由变量。此外,car
您可以使用(用于列表)更具描述性的名称来代替first
:
(defun pick (entries sub col)
(let ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries)))
(print choices)
(case (length choices)
(0 nil)
(1 (first choices))
(otherwise (nth (random (length choices)) choices)))))
这个函数将在别处定义,在代码片段的地方,它会被这样调用:
(pick entries sub col)
为了不计算(length choices)
两次,我们可以将其放入let
(需要成为let*
串行评估):
(defun pick (entries sub col)
(let* ((choices (remove-if (lambda (e)
(or (member e sub)
(member e col)))
entries))
(choices-length (length choices)))
(print choices)
(case choices-length
(0 nil)
(1 (first choices))
(otherwise (nth (random choices-length) choices)))))
最后一步(实际上是可选的,但也许你发现你有更多的序列减少你的选择,例如row
)将是一个小概括:
(defun pick (entries &rest exclusion-sequences)
(let* ((choices (remove-if (lambda (e)
(some #'identity
(mapcar (lambda (seq)
(member e seq))
exclusion-sequences)))
entries))
(choices-length (length choices)))
(print choices)
(case choices-length
(0 nil)
(1 (first choices))
(otherwise (nth (random choices-length) choices)))))
对该函数的调用具有相同的形式,但您现在可以使用任意数量的排除序列:
(pick entries col sub row ver ima fou)