Cláudio Ribeiro
Cláudio Ribeiro

Reputation: 1699

Lisp - Remove instances of a list of pairs from another list of pairs

I want to write a function in lisp that takes two lists of pairs and removes all occurrences of the first list from the second list. As an example, if we have list1 ((a b)(cd)) and list2 ((g h)(a b)(j i)), by calling this function the result would be ((g h)(j i)).

Until now i have the following code (which is not working):

(defun retira(obj l1)
  (cond ((null l1) ())
        ((equal obj (first l1)) (retira obj (rest l1)))
        (t (cons (first l1) (retira obj (rest l1))))))

(defun retira-ocupadas (tabuleiro lista-adj)
  (if (equal (first (todos-ocupados tabuleiro)) (first lista-adj))
    (retira (car (todos-ocupados tabuleiro)) lista-adj))

  (retira-ocupadas (rest (todos-ocupados tabuleiro)) (rest lista-adj))) 

Where retira should remove all occurrences of an object in a list and retira-ocupadas should take care of comparing, if the object from the first list is equal to an object from the second list. Todos-ocupados is a function that generates the first list.

This is currently not working, what am I doing wrong ?

Upvotes: 2

Views: 1089

Answers (4)

Rainer Joswig
Rainer Joswig

Reputation: 139411

(defun list-difference (list1 list2 &key (test #'eql))
  (loop for item in list1
        unless (member item list2 :test test)
        collect item))

Example:

CL-USER > (list-difference '((g h) (a b) (j i))
                           '((a b) (cd))
                           :test #'equal)
((G H) (J I))

Upvotes: 2

Hugh
Hugh

Reputation: 8932

set-difference will do this but will not necessarily preserve the order of the lists:

? (let ((list1 '((a b) (c d)))
        (list2 '((g h) (a b) (j i))))
    (set-difference list2 list1 :test 'equal))
((J I) (G H))

Upvotes: 0

Svante
Svante

Reputation: 51561

You want to remove any element of the second list that is a member of the first.

(defun remove-list (list-to-remove target-list)
  (remove-if (lambda (element)
               (member element list-to-remove
                       :test #'equal))
             target-list))

Please note the definition of equal, perhaps you want equalp instead (or perhaps you need to write your own pair-equal).

Upvotes: 3

SigmaX
SigmaX

Reputation: 483

Is this what you're trying to do?

(defun multi-remove (a b)
  (loop for e in b
        do (setf a (remove e a)))

This goes through every element of b and destructively removes all occurrences of it in a.

Upvotes: 1

Related Questions