我想创建一个函数来检查元素是否是列表的成员。该列表可以包含其他列表。 这是我到目前为止所得到的:
(defun subl(l)
(if (numberp l)
(if (= l 10)
(princ "Found"))
(mapcar 'subl l)))
现在我搜索的号码是硬编码的,是10
。我想以某种方式编写它,所以函数接受另一个参数(我正在搜索的数字)并在找到它时返回true
或1
。主要问题是我看不到控制mapcar
的方法。如果mapcar
列表,则subl
会在l
的每个元素上执行l
。但是,如何控制每次调用的返回值?
我想检查每个subl
来电的返回值,如果其中一个是true
或1
,则返回true
或1
直到最后一次递归调用。因此,如果元素包含在列表中,subl
会返回true
或one
,否则会返回nil
。
有什么想法吗?
答案 0 :(得分:2)
mapcar
是一个非常通用的原语,用于在列表上映射函数。您可以使用其中一个内置组合器,它更适合您要做的事情。查看member
函数。
答案 1 :(得分:2)
你的功能似乎同时扮演主要功能和助手的角色。这使得你的代码比它必须更难理解..
所以想象你把这两个分开了:
;; a predicate to check if an element is 10
(defun number10p (l)
(and (numberp l)
(= l 10)))
;; the utility function to search for 10 amongst elements
(defun sublistp (haystack)
(mapcar #'number10p haystack)))
但是当你执行(sublistp '(5 10 15 20))
时,你会得到(nil t nil nil)
。那是因为mapcar
列出了每个结果。对我而言,似乎你正在描述some因为它停在第一个真值。
(defun sublistp (haystack)
(some #'number10p haystack)))
(sublistp '(5 10 15 20)) ; ==> t
现在为了使它适用于任何数据类型,我们更改谓词并将其作为本地函数,我们有我们正在搜索的参数:
(defun sublistp (needle haystack)
(flet ((needlep (x)
(equal x needle)))
(some #'needlep haystack)))
(sublistp '(a b) '(a b c (a b) d e f)) ; ==> t
你也可以使用这样的匿名谓词:
(defun sublistp (needle haystack)
(some #'(lambda (x)
(equal x needle))
haystack))
这是member函数的实现,除了它将匹配作为真值返回。这没关系,因为nil
中只有CL
之内的任何内容都是正确的:
(member 10 '(5 10 15 20)) ; ==> (10 15 20)
修改强>
您评论了一个不同的答案,您需要使用mapcar
,在这种情况下将其与append
一起使用以获取所有匹配项的列表并检查列表是否包含大于0的元素:
(defun sublistp (needle haystack)
(flet ((needle-check (x)
(if (equal x needle) '(t) nil)))
(< 0 (length
(apply #'append
(mapcar #'needle-check haystack))))))
它的工作原理是,对于每个匹配,您将获得一个元素的列表,并且对于每个非匹配,您将获得一个空列表。附加列表时,如果不匹配,您将获得空列表。对于所有其他结果,您有匹配。这不是一个非常有效的实现。
答案 2 :(得分:2)
以下程序应如您所述处理;
(defun member-nested (el l)"whether el is a member of l, el can be atom or cons,
l can be list of atoms or not"
(cond
((null l) nil)
((equal el (car l)) t)
((consp (car l)) (or (member-nested el (car l))
(member-nested el (cdr l))))
(t (member-nested el (cdr l)))))