Another question about associate list

Whatever is on your mind, whether Lisp related or not.
Post Reply
joybee
Posts: 21
Joined: Wed Jan 07, 2009 1:49 pm

Another question about associate list

Post by joybee » Thu Aug 26, 2010 12:33 pm

I have create an associate list
mylist (list (list :a a)
(list :b b)
(list :c c))

later I need to check if the list contains an entry which has same value as a variable specified and if it does, then I want to delete the entry.

First I used member and it returned nil, why?
(dolist (myvar varlist)
(if (member myvar mylist) (setq mylist (delete myvar mylist))))

Then I took member function out and call delete directly, it still not working even though value at all the fields looked the same. Why?
(dolist (myvar varlist) (setq mylist (delete myvar mylist)))

Here is what I did, which is working:
(dolist (myvar varlist)
(dolist (elt mylist)
(if (equal myvar elt) (setq mylist (delete elt mylist)))
)
)
Is there another way to do it without using second dolist loop?


Puzzled!!!


Thanks!

Paul Donnelly
Posts: 148
Joined: Wed Jul 30, 2008 11:26 pm

Re: Another question about associate list

Post by Paul Donnelly » Thu Aug 26, 2010 10:23 pm

I think your problem is that you're forgetting the format of your alist. I don't know what varlist is, so I can't be sure.

Code: Select all

:b ≠ (:b b)
Keep in mind that any comparison you make will need to examine the first member of each alist entry, not the entry itself. You may find it easier to debug if you use remove instead of delete, and don't change mylist's binding. If you mess with your input data, you can easily get bad results when you test your function, because the input data isn't what you thought.

edgar-rft
Posts: 226
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: Another question about associate list

Post by edgar-rft » Thu Aug 26, 2010 11:37 pm

If you see the lists as sets you can use 'set-difference':

Code: Select all

(defvar *mylist* '((:a a) (:b b) (:c c) (:d d)))

(let* ((first-var  'c)
       (second-var 'd)
       (third-var  'e)
       (fourth-var 'f)
       (varlist (list first-var second-var third-var fourth-var)))
  (setq *mylist* 
        (set-difference *mylist* varlist 
                        :test (lambda (mylist-arg varlist-arg)
                                (eq (second mylist-arg) varlist-arg)))))

*mylist* => ((:a a) (:b b))
The 'eq' test-function inside the lambda construct must be adapted to the exact data types of the variables inside the 'varlist' and the 'value' fields of *mylist*. It must be a function that produces a reasonable result and no error if comparing both values.

joybee
Posts: 21
Joined: Wed Jan 07, 2009 1:49 pm

Re: Another question about associate list

Post by joybee » Fri Aug 27, 2010 10:18 am

The varlist is the same structure as mylist.

edgar-rft
Posts: 226
Joined: Fri Aug 06, 2010 6:34 am
Location: Germany

Re: Another question about associate list

Post by edgar-rft » Fri Aug 27, 2010 11:32 am

Code: Select all

(defvar *mylist*  (list (list :a 'a) (list :b 'b) (list :c 'c) (list :d 'd)))
(defvar *varlist* (list (list :c 'c) (list :d 'd) (list :e 'e) (list :f 'f)))

(setq *mylist*
      (set-difference *mylist* *varlist*
                      :test (lambda (mylist-arg varlist-arg)
                              (eq (second mylist-arg) (second varlist-arg)))))

*mylist* => ((:a a) (:b b))

audwinc
Posts: 12
Joined: Thu Sep 02, 2010 11:46 am

Re: Another question about associate list

Post by audwinc » Thu Sep 02, 2010 7:24 pm

joybee:

Your problem is that you were not doing a list comparison; you were doing an address comparison. The (list :a 'a) in *mylist* is NOT the same (list :a 'a) in *varlist* if you compare with eq. If you compare with equal, you will compare the elements. By default, member uses eq to compare. You need to specify the :test for delete as well.

Code: Select all

(defvar *mylist*  (list (list :a 'a) (list :b 'b) (list :c 'c) (list :d 'd)))
(defvar *varlist* (list (list :c 'c) (list :d 'd) (list :e 'e) (list :f 'f)))

(dolist (myvar *varlist*)
  (delete myvar *mylist* :test #'equal)) => ((:a 'a) (:b 'b))

;; alternative
(setf *mylist*
  (set-difference *mylist* *varlist* :test #'equal) =>
          ((:a 'a) (:b 'b))
             or
          ((:b 'b) (:a 'a))
The caveat with set-difference is that it treats your list like a set, and sets do not care about the order or frequency of their elements.

Post Reply