我需要一个能够检查列表a
是否是列表b
的正确子集的函数。到目前为止我的代码是:
(defun proper-subset (a b)
(cond
(( or (null b)(null b)) nil)
((equal a b) nil)
((find (car a) b) (proper-subset (cdr a) b))
)
)
find
会检查a
的每个元素是否在b
中。我知道null参数也需要一些工作,但我想弄清楚如何确定a
中b
的每个元素何时找到,b
有另一个元素。有内置的功能可以使这更容易,但这是一个功课问题所以我必须自己编写。任何提示或建议将不胜感激。
答案 0 :(得分:3)
Common Lisp定义了许多用于将列表作为集合处理的函数,因此您不需要编写自己的函数。特别是,有用的函数出现在The Conses Dictionary的底部。特别有用的是
subsetp
几乎做你想要的,但它正在检查不正确的子集。但是,请注意您可以使用这些函数来计算所需的内容。最直接的方法是检查 A 是 B 的子集,以及 B - A≠{} 。这符合您的描述,“a的每个元素都在b和b中找到了另一个元素”。
(defun proper-subsetp (a b)
(and (subsetp a b) ; every element of a is found in b
(not (endp (set-difference b a))))) ; b has another element
CL-USER> (proper-subsetp '(1 2 3) '(1 2 3 4))
T
CL-USER> (proper-subsetp '(1 2 3 4) '(1 2 3 4))
NIL
由于这些函数实际上采用了一些参数,可以让您确定元素的比较方式。您可以使用&rest
参数添加这些参数并应用:
(defun proper-subsetp (a b &rest keys)
(and (apply 'subsetp a b keys )
(not (endp (apply 'set-difference b a keys)))))
使用它,你可以,而不是直接比较元素,比较它们的长度:
CL-USER> (proper-subsetp '("a" "bb" "ccc") '("1" "22" "333") :key 'length)
NIL
CL-USER> (proper-subsetp '("a" "bb" "ccc") '("1" "22" "333" "4444") :key 'length)
T
答案 1 :(得分:0)
以下只会将if
添加到您提到的操作集中,但这实际上是一种非常糟糕的方式。如果这就是他们教给你的东西(你没有自愿参加)。现在是时候你会得到一本关于Lisp的好书并自己研究一下。在我看来,这个练习毫无意义。
(defun purge (element from-list)
(if (null from-list) nil
(if (equal element (car from-list))
(purge element (cdr from-list))
(cons (car from-list) (purge element (cdr from-list))))))
(defun proper-subset-p (suspect of)
(if (null suspect) (not (null of))
(if (not (equal (purge (car suspect) of) of))
(proper-subset-p
(purge (car suspect) suspect)
(purge (car suspect) of)) nil)))
同样的事情,但cond
(defun purge (element from-list)
(cond
((null from-list) nil)
((equal element (car from-list)) (purge element (cdr from-list)))
(t (cons (car from-list) (purge element (cdr from-list))))))
(defun proper-subset-p (suspect of)
(cond
((null suspect) (not (null of)))
((not (equal (purge (car suspect) of) of))
(proper-subset-p (purge (car suspect) suspect) (purge (car suspect) of)))
(t nil)))