implement equal function to recursion function

2019-09-11 08:53发布

问题:

I want to fix my own function that gives the same result with the default intersection function. I've been trying to write a lisp code which prints same elements in the two lists. My code works for it. But it doesn't work for nested lists. How can I fix this?

(defun printelems (L1 L2) 
(cond 
((null L1) nil) ((member (first L1) L2) (cons (first L1) (printelems (rest L1) L2)))
(t (printelems (rest L1) L2))))

Expected inputs and outputs

(printelems '(2 3 5 7) '( 2 3)) => It works
=> (2 3)
(printelems '(a b '(c f)) '(a d '(c f) e)) => It doesn't work.
=> (a (c f))

Edit

Using the default intersection function works as intended. How can I use the equal function in my recursive function?

For default intersection,

(intersection '(a b (c f)) '(a d (c f) e) :test 'equal)
((C F) A)
(intersection '(a b (c f)) '(a d c f e) :test 'equal)
(A)

My intersection,

(printelems  '(a b (c f)) '(a d c f e))
(A C F)
(printelems  '(a b (c f)) '(a d (c f) e) )
(A C F)

My edited code:

(defun flatten (l)
  (cond ((null l) nil)
    ((atom (car l)) (cons (car l) (flatten (cdr l))))
    (t (append (flatten (car l)) (flatten (cdr l))))))

(defun printelemsv1(list1 list2)
  (cond
   ((null list1) nil)
   (((member (first list1) list2) (cons (first list1) (printelemsv1 (rest list1) list2)))
   (t (printelemsv1 (rest list1) list2)))))


(defun printelems (L1 L2)
   (printelemsv1 (flatten L1) (flatten L2)))

回答1:

Common Lisp already has an intersection function. If you want to compare sublists like (C F), you'll want to use equal or equalp as the test argument.

(intersection '(a b '(c f)) '(a d '(c f) e) :test 'equal)
;=> ('(C F) A)

While it doesn't change how intersection works, you probably don't really want quote inside your list. Quote isn't a list creation operator; it's a "return whatever the reader read" operator. The reader can read (a b (c f)) as a list of two symbols and a sublist, so (quote (a b (c f))), usually abbreviated as '(a b (c f)) is fine. E.g.:

(intersection '(a b (c f)) '(a d (c f) e) :test 'equal)
;=> ((C F) A)


回答2:

It's always helpful when you provide an example of input and the expected output. I assume you mean you have two lists like '(1 (2 3) 4) and '((1) 2 5 6) that the function should produce '(1 2). In this case you can just flatten the two lists before giving them to printelems.

Since I'm not familiar with Common-Lisp itself I will leave you with one example and a link.

(defun flatten (structure)
  (cond ((null structure) nil)
        ((atom structure) (list structure))
        (t (mapcan #'flatten structure))))

Flatten a list - Rosetta Code

flatten takes an arbitrary s-expression like a nested list '(1 (2 3) 4) and returns '(1 2 3 4).

So now you just have to write a new function in which you use your printelems as a helper function and give it flattened lists.

(defun printelems.v2 (L1 L2)
   (printelems (flatten L1) (flatten L2)))

Take this with a grain of salt, since as said before I'm not familiar with Common-Lisp, so appologies in advance for any potential syntax errors.