From: Mad Scientist Jr
Subject: searching by a key in a sub-sub-list without iteration?
Date: 
Message-ID: <1161897442.760713.41880@m7g2000cwm.googlegroups.com>
Given the list below, you can retrieve a sub list with assoc, like:

  (assoc "vegetable" MyList)

and you can retrieve a sub-sub list like:

(cadr
  (assoc
    "grasshopper"
    (cadr
      (assoc
        "animal"
        MyList
      )
    )
  )
)


But is there some way to retrieve the sub-sub-list without knowing the
sub-list's key, and without having to iterate through all the sublists,
like:

  (RetrieveSubSubList "grasshopper")

?

(You can assume the sub-sub list's key is unique.)

Much appreciated...


----------

(set! MyList '
  ( ; my list
    ("animal"
      (
        (
          "panda"
          (
            ("description" "big news when they give birth")
            ("price" 75000)
            ("color" "black and white")
          )
        )
        (
          "lion"
          (
            ("description" "very dangerous")
            ("price" 50000)
            ("color" "golden")
          )
        )
        (
          "grasshopper"
          (
            ("description" "contains lots of protein")
            ("price" .10)
            ("color" "green")
          )
        )
      )
    ) ; animal
    ("mineral"
      (
        (
          "bicycle"
          (
            ("description" "good on gas")
            ("price" 200)
            ("color" "blue")
          )
        )
        (
          "automobile"
          (
            ("description" "good in rain")
            ("price" 20000)
            ("color" "red")
          )
        )
        (
          "rocket"
          (
            ("description" "fast and dangerous")
            ("price" 1000000)
            ("color" "silver")
          )
        )
      )
    ) ; mineral
    ("vegetable"
      (
        (
          "tomato"
          (
            ("description" "round and tasty")
            ("price" .75)
            ("color" "red")
          )
        )
        (
          "squash"
          (
            ("description" "comes in many shapes and sizes")
            ("price" .50)
            ("color" "yellow")
          )
        )
        (
          "broccoli"
          (
            ("description" "healthy")
            ("price" .25)
            ("color" "green")
          )
        )
      )
    ) ; vegetable
  ) ; my list
) ; set!

From: ··············@gmail.com
Subject: Re: searching by a key in a sub-sub-list without iteration?
Date: 
Message-ID: <1161898910.032406.177010@i42g2000cwa.googlegroups.com>
On Oct 26, 4:17 pm, "Mad Scientist Jr" <···············@yahoo.com>
wrote:
> Given the list below, you can retrieve a sub list with assoc, like:
>
>   (assoc "vegetable" MyList)
>
> and you can retrieve a sub-sub list like:
>
> (cadr
>   (assoc
>     "grasshopper"
>     (cadr
>       (assoc
>         "animal"
>         MyList
>       )
>     )
>   )
> )

Do you think assoc-list of assoc-lists is a good data structure for
your problem? You may want to store everything in structure:

(defstruct something
  category
  name
  description
  price
  color)

(defun find-something-by-name (lst name)
  (find name lst :key #'something-name :test #'string-equal))

(defvar creatures)
(setf creatures
      (list
       (make-something :category "animal" :name "panda"
		       :description "big news when they give birth"
		       :price 75000 :color "black and white")
       (make-something :category "animal" :name "lion"
		       :description "very dangerous"
		       :price 50000 :color "golden")
       (make-something :category "mineral" :name "bicycle"
		       :description "good on gas" :price 200
		       :color "blue")))

(find-something-by-name creatures "panda")

=>
#S(SOMETHING
   :CATEGORY "animal"
   :NAME "panda"
   :DESCRIPTION "big news when they give birth"
   :PRICE 75000
   :COLOR "black and white")

Otherwise, you may write your own function as Pascal mentioned.
From: Pascal Bourguignon
Subject: Re: searching by a key in a sub-sub-list without iteration?
Date: 
Message-ID: <87ejsurck1.fsf@thalassa.informatimago.com>
"Mad Scientist Jr" <···············@yahoo.com> writes:

> Given the list below, you can retrieve a sub list with assoc, like:
>
>   (assoc "vegetable" MyList)
>
> and you can retrieve a sub-sub list like:
>
> (cadr
>   (assoc
>     "grasshopper"
>     (cadr
>       (assoc
>         "animal"
>         MyList))))
>
>
> But is there some way to retrieve the sub-sub-list without knowing the
> sub-list's key, and without having to iterate through all the sublists,
> like:
>
>   (RetrieveSubSubList "grasshopper")
>
> ?
>
Yes, there's some way.

For example, you could write a function to do that.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Wanna go outside.
Oh, no! Help! I got outside!
Let me back inside!
From: Rob Warnock
Subject: Re: searching by a key in a sub-sub-list without iteration?
Date: 
Message-ID: <6K-dnaPkL6a7LtzYnZ2dnUVZ_oKdnZ2d@speakeasy.net>
Mad Scientist Jr <···············@yahoo.com> wrote:
+---------------
| But is there some way to retrieve the sub-sub-list without knowing the
| sub-list's key, and without having to iterate through all the sublists,
| like: (RetrieveSubSubList "grasshopper")
+---------------

No, but the CL functions TREE-EQUAL (given an appropriate :TEST arg)
or SUBST-IF can be perverted into serving as a tree walker for you.

But just writing a simple one for yourself is easier, and will
help you a lot in learning the language. This one took me barely
five minutes to code and test [and only 7 lines of code, 10 if
you include the doc string]:

    > (describe #'tree-assoc)

    #<Function TREE-ASSOC {58A0D1F9}> is function.
    Arguments:
      (tag tree &key (test #'eql) (key #'identity))
    Function documentation:
      Do a left-to-right depth-first walk of TREE and return the first
      cons in TREE whose car (as transformed by the KEY) satisfies the 
      TEST when compared with ITEM, or NIL if no such cons is found.
    Its defined argument types are:
      (T T &KEY (:TEST T) (:KEY T))
    Its result type is:
      *
    On Thursday, 10/26/06 11:50:42 pm PDT it was compiled from:
    #(#'(LAMBDA # #))

    > (tree-assoc "Grasshopper" mylist) 

    NIL
    > (tree-assoc "Grasshopper" mylist :test #'equal)

    NIL
    > (tree-assoc "Grasshopper" mylist :test #'equalp)

    ("grasshopper"
     (("description" "contains lots of protein") ("price" 0.1)
      ("color" "green")))
    > 

Yes, I deliberately captialized "Grasshopper", to make it a
better example of :TEST arguments in traversal functions.


-Rob

p.s. Do be sure to implement the :KEY convention in your version
of TREE-ASSOC, too, because that lets you do fun stuff like this:

    > (flet ((my-key (x)
	      (format t "Looking at ~S~%" x)
	      x))
	(tree-assoc "Grasshopper" mylist :test #'equalp :key #'my-key))
    Looking at "animal"
    Looking at "panda"
    Looking at "description"
    Looking at "big news when they give birth"
    Looking at "price"
    Looking at 75000
    Looking at "color"
    Looking at "black and white"
    Looking at "lion"
    Looking at "description"
    Looking at "very dangerous"
    Looking at "price"
    Looking at 50000
    Looking at "color"
    Looking at "golden"
    Looking at "grasshopper"
    ("grasshopper"
     (("description" "contains lots of protein") ("price" 0.1)
      ("color" "green")))
    > 

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607