Reputation: 3164
I want to make a function that checks if an element is a member of a list. The list can contain other lists. This is what I came with so far:
(defun subl(l)
(if (numberp l)
(if (= l 10)
(princ "Found"))
(mapcar 'subl l)))
Now the number I am searching for is hard-coded and it is 10
. I would like to write it somehow so the function takes another parameter(the number I am searching for) and returns true
or 1
when it finds it. The main problem is that I can't see a way to control mapcar
. mapcar
executes subl
on each element of l
, if l
si a list. But how can I controll the returned values of each call?
I would like to check the return value of each subl
call and if one of it is true
or 1
to return true
or 1
till the last recursive call. So in the end subl
returns true
or one
if the element is contained in the list or nil
otherwise.
Any idea?
Upvotes: 0
Views: 5891
Reputation: 3070
This procedure below should process as you have described;
(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)))))
Upvotes: 2
Reputation: 48745
Your function seems to play the role of main function and helper at the same time. That makes your code a lot more difficult to understand than it has to be..
So imagine you split the two:
;; 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)))
But here when you do (sublistp '(5 10 15 20))
you'll get (nil t nil nil)
back. Thats because mapcar
makes a list of every result. For me it seems you are describing some since it stops at the first true value.
(defun sublistp (haystack)
(some #'number10p haystack)))
(sublistp '(5 10 15 20)) ; ==> t
Now to make it work for any data type we change the predicate and make it as a local function where we have the argument we are searching for:
(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
You can also do this with an anonymous predicate like this:
(defun sublistp (needle haystack)
(some #'(lambda (x)
(equal x needle))
haystack))
An implementation of this is the member function, except it returns the match as truth value. That's ok since anything but nil
is true in CL
:
(member 10 '(5 10 15 20)) ; ==> (10 15 20)
EDIT
You commented on a different answer that you are required to use mapcar
in that case use it together with append
to get a list of all matches and check if the list has greater than 0 elements:
(defun sublistp (needle haystack)
(flet ((needle-check (x)
(if (equal x needle) '(t) nil)))
(< 0 (length
(apply #'append
(mapcar #'needle-check haystack))))))
How it works is that for each match you get a list of one element and for every non match you get an empty list. When appending the lists you'll get the empty list when there is not match. For all other results you have a match. This is not a very efficient implementation.
Upvotes: 2