尝试 return 列表中的独特元素
Trying to return unique elements from list
我真的是 Lisp 编程的新手,因此我更愿意自己解决它,所以任何提示都将不胜感激!我的目标是检索随机挑选的唯一项目的列表。下面的代码有时可以 return 一个列表,例如 ("has a ball" "has a ball")。我更希望它检查列表的成员是否是唯一的,如果不是,则丢弃相同的项目之一并添加一个随机的唯一成员。
(defvar *pirateAttributes*
(list "has a pirate costume" "has a wooden leg" "has a
ball")
)
(defun select-attributes (n)
(loop repeat n
collect (nth (random (length *pirateAttributes*))
*pirateAttributes*)
)
)
(select-attributes 2)
UPDATE1:我通过谷歌搜索一堆并以某种方式找到了一种方法。我相信有更好的方法。因为我有一个工作版本,所以欢迎您的最佳答案!这次我将循环保持得更长,并决定修剪或使用递归来获得所需数量的属性。如果有很多属性,它的扩展性可能会很差。但事情就是这样...
(defun select-attributes (n)
"returns n randomly picked attributes from *pirateAttributes* as a list"
(setf mylist '())
(loop repeat (+ n 10)
do (push (nth (random (length *pirateAttributes*)) *pirateAttributes*) mylist)
(print mylist)
)
(setf mylist (remove-duplicates mylist) )
(print mylist)
(setf listlen (length mylist))
(case n
(1 (if(= listlen 1)(values)(setf mylist (first mylist))))
(2 (if(= listlen 2)(values)(setf mylist (cdr mylist))))
(3 (if(= listlen 3)(values)(select-attributes n)))
)
)
一个相当简单的解决方案是获取属性列表并对其执行 Fisher-Yates shuffle。
您可以创建一个函数,returns 一个包含属性列表的随机元素的新列表。下面的 shuffle
函数从输入列表中选择一个随机元素,并将其转化为对剩余元素进行混洗的结果。
然后你可以使用subseq
函数从打乱后的列表中取出你需要的元素个数:
(defvar *pirate-attributes*
(list "has a pirate costume"
"has a wooden leg"
"has a ball"
"has a parrot"
"has a monkey"
"has a saber"
"has an eye patch"
"has a bottle of rum"))
(defun shuffle (xs)
(if (or (null xs)
(null (cdr xs)))
xs
(let* ((i (random (length xs)))
(x (nth i xs)))
(cons x (shuffle (append (subseq xs 0 i)
(subseq xs (1+ i))))))))
(defun select-random-n (xs n)
(subseq (shuffle xs) 0 n))
示例 REPL 交互:
CL-USER> (select-random-n *pirate-attributes* 3)
("has a bottle of rum" "has a pirate costume" "has an eye patch")
CL-USER> (select-random-n *pirate-attributes* 3)
("has an eye patch" "has a ball" "has a bottle of rum")
CL-USER> (select-random-n *pirate-attributes* 2)
("has a monkey" "has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a ball" "has a saber" "has an eye patch" "has a wooden leg"
"has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a wooden leg" "has a monkey" "has a ball" "has a pirate costume"
"has a parrot")
我真的是 Lisp 编程的新手,因此我更愿意自己解决它,所以任何提示都将不胜感激!我的目标是检索随机挑选的唯一项目的列表。下面的代码有时可以 return 一个列表,例如 ("has a ball" "has a ball")。我更希望它检查列表的成员是否是唯一的,如果不是,则丢弃相同的项目之一并添加一个随机的唯一成员。
(defvar *pirateAttributes*
(list "has a pirate costume" "has a wooden leg" "has a
ball")
)
(defun select-attributes (n)
(loop repeat n
collect (nth (random (length *pirateAttributes*))
*pirateAttributes*)
)
)
(select-attributes 2)
UPDATE1:我通过谷歌搜索一堆并以某种方式找到了一种方法。我相信有更好的方法。因为我有一个工作版本,所以欢迎您的最佳答案!这次我将循环保持得更长,并决定修剪或使用递归来获得所需数量的属性。如果有很多属性,它的扩展性可能会很差。但事情就是这样...
(defun select-attributes (n)
"returns n randomly picked attributes from *pirateAttributes* as a list"
(setf mylist '())
(loop repeat (+ n 10)
do (push (nth (random (length *pirateAttributes*)) *pirateAttributes*) mylist)
(print mylist)
)
(setf mylist (remove-duplicates mylist) )
(print mylist)
(setf listlen (length mylist))
(case n
(1 (if(= listlen 1)(values)(setf mylist (first mylist))))
(2 (if(= listlen 2)(values)(setf mylist (cdr mylist))))
(3 (if(= listlen 3)(values)(select-attributes n)))
)
)
一个相当简单的解决方案是获取属性列表并对其执行 Fisher-Yates shuffle。
您可以创建一个函数,returns 一个包含属性列表的随机元素的新列表。下面的 shuffle
函数从输入列表中选择一个随机元素,并将其转化为对剩余元素进行混洗的结果。
然后你可以使用subseq
函数从打乱后的列表中取出你需要的元素个数:
(defvar *pirate-attributes*
(list "has a pirate costume"
"has a wooden leg"
"has a ball"
"has a parrot"
"has a monkey"
"has a saber"
"has an eye patch"
"has a bottle of rum"))
(defun shuffle (xs)
(if (or (null xs)
(null (cdr xs)))
xs
(let* ((i (random (length xs)))
(x (nth i xs)))
(cons x (shuffle (append (subseq xs 0 i)
(subseq xs (1+ i))))))))
(defun select-random-n (xs n)
(subseq (shuffle xs) 0 n))
示例 REPL 交互:
CL-USER> (select-random-n *pirate-attributes* 3)
("has a bottle of rum" "has a pirate costume" "has an eye patch")
CL-USER> (select-random-n *pirate-attributes* 3)
("has an eye patch" "has a ball" "has a bottle of rum")
CL-USER> (select-random-n *pirate-attributes* 2)
("has a monkey" "has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a ball" "has a saber" "has an eye patch" "has a wooden leg"
"has a parrot")
CL-USER> (select-random-n *pirate-attributes* 5)
("has a wooden leg" "has a monkey" "has a ball" "has a pirate costume"
"has a parrot")