From: Luke J Crook
Subject: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <uPBh8.302$SL2.1019044@twister.socal.rr.com>
A very newbie question:

I have an array of objects (CLOS), each object in the array contains a
unique identifier (number). I would like to return an object from the array
based on this identifier. Using ASSOC to return an item from an array of
numbers is easy.... is there some way to use ASSOC in my case or must I
write a function ? I was thinking something along the lines of.....

(ASSOC 2001 alist '(get-id my-object))

Here, ASSOC evaluates the (return-id my-object) method for each object in
the array and returns the object where the ID equals 2001.

Anyone know of an existing mechanism in LISP which allows this ?

-Luke Crook

From: Michael Parker
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <217DD639F690AEA9.CA51E15D09444F34.4FB36FDCDA20AAD9@lp.airnews.net>
Luke J Crook wrote:
> 
> A very newbie question:
> 
> I have an array of objects (CLOS), each object in the array contains a
> unique identifier (number). I would like to return an object from the array
> based on this identifier. Using ASSOC to return an item from an array of
> numbers is easy.... is there some way to use ASSOC in my case or must I
> write a function ? I was thinking something along the lines of.....
> 
> (ASSOC 2001 alist '(get-id my-object))
> 
> Here, ASSOC evaluates the (return-id my-object) method for each object in
> the array and returns the object where the ID equals 2001.
> 
> Anyone know of an existing mechanism in LISP which allows this ?

Won't (find 2001 obj-arr :key #'get-id) do the trick?
From: Luke Crook
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <a68gi6$9rm@dispatch.concentric.net>
"Michael Parker" <·······@pdq.net> wrote in message
·······················································@lp.airnews.net...
> Luke J Crook wrote:

> Won't (find 2001 obj-arr :key #'get-id) do the trick?

Many thanks, yes FIND does work... However ASSOC does not, even though I
have a LIST and not an array as I stated before... The ASSOC at the end
returns NIL. Could someone please explain why ?

Here is my code:

(defclass obj ()
  ((obj-id :initform nil :accessor obj-id :initarg obj-id)))

(setq list-of-objs nil)
(dotimes (i 100 "all done")
  (setq list-of-objs (cons (make-instance 'obj 'obj-id (* i 100))
list-of-objs)))

(setq temp-obj (find 1000 list-of-objs :key #'obj-id))
(format T "~&obj = ~s, obj-id = ~s~%" temp-obj (obj-id temp-obj))

(setq temp-obj (assoc 1000 list-of-objs :key #'obj-id))
(format T "~&obj = ~s, obj-id = ~s~%" temp-obj (obj-id temp-obj))

-Luke
From: Barry Margolin
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <nJPh8.16$0%4.145@paloalto-snr2.gtei.net>
In article <··········@dispatch.concentric.net>,
Luke Crook <······@wsbnet.com> wrote:
>"Michael Parker" <·······@pdq.net> wrote in message
>·······················································@lp.airnews.net...
>> Luke J Crook wrote:
>
>> Won't (find 2001 obj-arr :key #'get-id) do the trick?
>
>Many thanks, yes FIND does work... However ASSOC does not, even though I
>have a LIST and not an array as I stated before... The ASSOC at the end
>returns NIL. Could someone please explain why ?

ASSOC requires the list to be an association list, which means it's of the
form:

((key1 . value1) (key2 . value2) ...)

When :KEY is used with ASSOC, it's used to find the slot *within* each keyN
object.

You just have a list of objects, not a list of associations.  That's what
FIND is designed to work with.

The relationship is like this:

(defun assoc (object alist &key (key #'identity))
  (find object alist :key (lambda (x) (funcall key (car x)))))

i.e. ASSOC always performs an additional CAR call before calling the key
you supply.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Luke Crook
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <a68i3v$9ro@dispatch.concentric.net>
"Barry Margolin" <······@genuity.net> wrote in message
·····················@paloalto-snr2.gtei.net...
> In article <··········@dispatch.concentric.net>,
> Luke Crook <······@wsbnet.com> wrote:

> ASSOC requires the list to be an association list, which means it's of the
> form:
>
> ((key1 . value1) (key2 . value2) ...)
>
> When :KEY is used with ASSOC, it's used to find the slot *within* each
keyN
> object.

Aha! Thank you for the explanation.

-Luke
From: Kent M Pitman
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <sfwd6ygqcen.fsf@shell01.TheWorld.com>
Barry Margolin <······@genuity.net> writes:

> The relationship is like this:
> 
> (defun assoc (object alist &key (key #'identity))
>   (find object alist :key (lambda (x) (funcall key (car x)))))
>
> i.e. ASSOC always performs an additional CAR call before calling the key
> you supply.

Actually, not to be a real nitpicker here, but ok, maybe I am.
I wanted to slip this in anyway, though, because a lot of people 
aren't aware that ASSOC has one other irritating (or useful? not
to me, but maybe to someone) historical oddity that makes it hard to
describe in terms of FIND (not impossible, just wierd).

That is: ASSOC ignores NILs in the set of thing to be found.  It
doesn't just blindly CAR into them and call the test, it just treats
them as if they are not there.  To abuse an analogy [and please,
newbies, close your eyes now], the relation is more like:

 (defun kmp-assoc (object alist &key (key #'identity) (test #'eql))
   (let ((skip '#:skip))
     (find object alist
           :key (lambda (x)
                  (if (not x) skip (funcall key (car x))))
           :test (lambda (x y)
                   (if (eq y skip) nil
                     (funcall test x y))))))

and less like:

 (defun barmar-assoc (object alist &key (key #'identity))
   (find object alist :key (lambda (x) (funcall key (car x)))))

although one could say that under the vagueness of the simile invoked by
"like" you perhaps didn't want to treat this detail and your example could
have been, er, like correct.  (Unless you were speaking valspeak, but I 
think that, like, requires more commas, like, fer sure...)

Some test cases of interest might be:

 ;; Test #1 - Does it signal a gratuitous error?
 ;; This case is not applicable in Barry's implementation above because
 ;; his doesn't have a :test argument.

 (find 3 '((4 . 7) nil (5 . 2) (3 . 9) (8 . 2)) :test #'= :key #'car)
 Error: In = of (3 NIL) arguments should be of type NUMBER.

 (cl:assoc 3 '((4 . 7) nil (5 . 2) (3 . 9) (8 . 2)) :test #'=)
 => (3 . 9)

 (kmp-assoc 3 '((4 . 7) nil (5 . 2) (3 . 9) (8 . 2)) :test #'=)
 => (3 . 9)

 ;; Test #2 - Does it return a wrong value?
 ;; This is applicable to Barry's implementation.
 ;; I've given marked his as BARMAR-ASSOC here.

 (assoc nil '((t . 7) nil (nil . 2)))
 => (NIL . 2)

 => (kmp-assoc nil '((t . 7) nil (nil . 2)))
 (NIL . 2)

 (barmar-assoc nil '((t . 7) nil (nil . 2)))
 => NIL

 (find nil '((t . 7) nil (nil . 2)))
 => NIL
From: Barry Margolin
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <nyRh8.20$0%4.316@paloalto-snr2.gtei.net>
In article <···············@shell01.TheWorld.com>,
Kent M Pitman  <······@world.std.com> wrote:
>although one could say that under the vagueness of the simile invoked by
>"like" you perhaps didn't want to treat this detail and your example could
>have been, er, like correct.  (Unless you were speaking valspeak, but I 
>think that, like, requires more commas, like, fer sure...)

That was my intent.  Since the issue that he was confused about was the way
the test was used, I was only demonstrating that one feature.  That's also
why my sample implementation was missing the other keyword options that
ASSOC takes.  Adding everything else would have made it more difficult for
him to see the point I was making.

-- 
Barry Margolin, ······@genuity.net
Genuity, Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Nils Goesche
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <a68pom$cn65l$1@ID-125440.news.dfncis.de>
In article <···············@shell01.TheWorld.com>, Kent M Pitman wrote:
> I wanted to slip this in anyway, though, because a lot of people 
> aren't aware that ASSOC has one other irritating (or useful? not
> to me, but maybe to someone) historical oddity that makes it hard to
> describe in terms of FIND (not impossible, just wierd).
> 
> That is: ASSOC ignores NILs in the set of thing to be found.  It
> doesn't just blindly CAR into them and call the test, it just treats
> them as if they are not there.

Amazing!  I really wonder why this is so.  I guess somebody had
already written a lot of code where he removed elements from
assoc lists by setting them to NIL or some other weirdness.

Regards,
-- 
Nils Goesche
  "The sooner all the animals are dead, the sooner we'll find
   their money."                              -- Ed Bluestone
PGP key ID 0x42B32FC9
From: Kent M Pitman
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <sfwzo1kro2p.fsf@shell01.TheWorld.com>
Nils Goesche <······@cartan.de> writes:

> In article <···············@shell01.TheWorld.com>, Kent M Pitman wrote:
> > I wanted to slip this in anyway, though, because a lot of people 
> > aren't aware that ASSOC has one other irritating (or useful? not
> > to me, but maybe to someone) historical oddity that makes it hard to
> > describe in terms of FIND (not impossible, just wierd).
> > 
> > That is: ASSOC ignores NILs in the set of thing to be found.  It
> > doesn't just blindly CAR into them and call the test, it just treats
> > them as if they are not there.
> 
> Amazing!  I really wonder why this is so.  I guess somebody had
> already written a lot of code where he removed elements from
> assoc lists by setting them to NIL or some other weirdness.

Yes, I'm pretty sure that's it.  It's some historical accomodation to
this way of doing the "makunbound" thing in spaghetti stacks or some
such... it's dangerous to actually remove the backbone cells because
of the sharing issues, perhaps.

What's even weirder is that this kind of strangeness can exist in the 
semantics of a popular function for a long time and yet my guess is that
most people both don't know and don't run into any case that matters.
There were a ton of similar effects in SUBST and EQUAL when we were
comparing dialects and trying to come up with a definition of these for
CL's SUBST and EQUAL.  Every dialect differed and most people who used
multiple dialects were oblivious to the differences, just sort of blindly
assuming that a generic knowledge of the basic idea would get them by.
And I suppose in most cases it did.  But it's a little scary...
From: Coby Beck
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <9XQh8.92939$kb.5601382@news1.calgary.shaw.ca>
"Luke Crook" <······@wsbnet.com> wrote in message
···············@dispatch.concentric.net...
> "Michael Parker" <·······@pdq.net> wrote in message
> ·······················································@lp.airnews.net...
> > Luke J Crook wrote:

Others answered your question, I will just offer some obvious stylistic
suggestions.

> Here is my code:
>
> (defclass obj ()
>   ((obj-id :initform nil :accessor obj-id :initarg obj-id)))

initargs are normally keywords.

 :initarg :obj-id

>
> (setq list-of-objs nil)

It is unreliable to setq an undefined variable.

(defvar list-of-objs nil)

> (dotimes (i 100 "all done")
>   (setq list-of-objs (cons (make-instance 'obj 'obj-id (* i 100))
> list-of-objs)))

Check out PUSH.

(dotimes (i 100)
   (push (make-instance 'obj :obj-id (* i 100))
         list-of-objs))


>
> (setq temp-obj (find 1000 list-of-objs :key #'obj-id))
> (format T "~&obj = ~s, obj-id = ~s~%" temp-obj (obj-id temp-obj))
>

If it is not worth defvar'ing, just use a let:
(let ((temp (find 1000 list-of-objs :key #'obj-id))))
    (format T "~&obj = ~s, obj-id = ~s~%" temp-obj (obj-id temp-obj)))


> (setq temp-obj (assoc 1000 list-of-objs :key #'obj-id))
> (format T "~&obj = ~s, obj-id = ~s~%" temp-obj (obj-id temp-obj))
>

You're typing "T" rather than "t".  While lisp is a case sensitive, the
reader usually is not by default settings, converting everything to
upper-case behind the scenes.  Normal lisp style does not mix case and
everywhere I've used lisp we did everything in all lowercase.

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Lieven Marchand
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <86it88x28l.fsf@wyrd.be>
"Luke J Crook" <······@socal.rr.com> writes:

> A very newbie question:
> 
> I have an array of objects (CLOS), each object in the array contains a
> unique identifier (number). I would like to return an object from the array
> based on this identifier. Using ASSOC to return an item from an array of
> numbers is easy.... 

ASSOC doesn't work on arrays but on lists.

> is there some way to use ASSOC in my case or must I
> write a function ? I was thinking something along the lines of.....
> 
> (ASSOC 2001 alist '(get-id my-object))
> 
> Here, ASSOC evaluates the (return-id my-object) method for each object in
> the array and returns the object where the ID equals 2001.

Assuming we're talking about lists, use the :key argument.

(assoc 2001 alist :key #'get-id)

-- 
Honest praise, this stony part insisted, was what the bunglers of the world 
heaped on the heads of the barely competent.                -- Stephen King
From: Luke Crook
Subject: Re: ASSOC using an object method to match item in an Array?
Date: 
Message-ID: <a68glp$9rl@dispatch.concentric.net>
"Lieven Marchand" <···@wyrd.be> wrote in message
···················@wyrd.be...
> "Luke J Crook" <······@socal.rr.com> writes:
>
> ASSOC doesn't work on arrays but on lists.
>
> Assuming we're talking about lists, use the :key argument.
>
> (assoc 2001 alist :key #'get-id)

Yes, I was mistaken. I am indeed working with a list built from CONS.
However ASSOC does not seem to work, FIND does. I have posted some code in a
previous post.

-Luke