尝试 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")