试图从列表中返回唯一元素

问题描述 投票:1回答:1

我真的是Lisp编程的新手,因此我更愿意自己摸索,所以任何提示都会感激不尽。我的目标是检索一个随机挑选的唯一项目的列表。下面的代码有时会返回一个列表,如("有一个球""有一个球")。我希望它能检查列表中的成员是否是唯一的,如果不是,则丢弃其中一个相同的项目,并添加一个随机的唯一成员。

   (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)))
    )   
)
list loops random common-lisp unique
1个回答
3
投票

一个合理的简单的解决方案是将属性列表并执行 费舍尔-耶茨洗牌 上。

你可以创建一个函数,返回一个包含属性列表中洗牌元素的新列表。列表中的 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")
© www.soinside.com 2019 - 2024. All rights reserved.