This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Find a value in an association list

3 posts · 7122 views

Dear all,

I was wondering how I could find a value in an association list recursively, even if this value is inside a vector. Let me give you an example. I have this list (response from the Discogs API), let's call it discogs
((resp (version . "2.0")
       (release
        (data_quality . "Correct")
        (tracklist . [... ... ...])
        (master_id . 18609)
        (resource_url . "http://api.discogs.com/releases/798045")
        (formats . [...])
        (artists . [...])
        (uri . "http://www.discogs.com/Photek-Natural-Born-Killa-EP/release/798045")
        (companies . [])
        (notes . "...")
        (country . "UK")
        (title . "Natural Born Killa EP") ...)
       (status . t)))
At the moment I have a function which can find any value as long as it is in a nested list:
(defun tree-assoc (key tree)
  (when (consp tree)
    (destructuring-bind (x . y)  tree
      (if (eql x key) tree
        (or (tree-assoc key x) (tree-assoc key y))))))
So for example,
(cdr (tree-assoc 'title discogs))
will find the value "Natural Born Killa EP". Fine.

However, the name of the artist is inside a vector, in the cons cell (artists . [...]). This vector contains another nested list, like this:
[((id . 417) (resource_url . "http://api.discogs.com/artists/417") (role . "") (tracks . "") (anv . "") (name . "Photek") (join . ""))]
So I'm looking for a way to modify tree-assoc so the recursion won't be broken by a vector. How could I do that?

Thanks,

Beltxarga

Last edited by Beltxarga on , edited 1 time in total.

Re: Find a value in an association list

(defun recursive-assoc (key data)
  (cond ((consp data) <recursive-code-for-handling-nonempty-lists>)
        ((vectorp data) <recursive-code-for-handling-vectors>)
        (t (error "not a nonempty list or vector: %s" data))))

Re: Find a value in an association list

edgar-rft wrote:
(defun recursive-assoc (key data)
  (cond ((consp data) <recursive-code-for-handling-nonempty-lists>)
        ((vectorp data) <recursive-code-for-handling-vectors>)
        (t (error "not a nonempty list or vector: %s" data))))
Thank you edgar-rift! It was very useful. I came up with this:
(defun btx/discogs-get-value (data key)
  (cond
   ((consp data) (destructuring-bind (x . y) data
		   (if (eql x key) y
		     (or (btx/discogs-get-value x key)
			      (btx/discogs-get-value y key)))))
   ((vectorp data) (btx/discogs-get-value (elt data 0) key))))
And it seems to work! I would very much like your opinion about the way I'm getting details about the release, like the artist name, title... If you look at the tree, you can find the artist name by going through a 'artists' index, itself associated with a vector, which contains a 'name' index, like this :
   (artists .
	    [((id . 417)
	      (resource_url . "http://api.discogs.com/artists/417")
	      (role . "")
	      (tracks . "")
	      (anv . "")
	      (name . "Photek")
	      (join . ""))])
So the value associated with that 'name' index is the name of the artist. So I simply came up with this:
(defun btx/discogs-get-artist-name (release)
  (let ((release_info (btx/discogs-query release)))
    (btx/discogs-get-value (btx/discogs-get-value release_info 'artists) 'name)))
I think it is a simple but inelegant way to walk the tree, to call btx/discogs-get-value multiple times recursively, even if I don't have to call it more than 2 times to access most of the release details. BTW, btx/discogs-query-release is for getting the tree that you saw above, of course. My idea was to allow multiple parameters in btx/discogs-get-value, but the recursion make it quite complicated for me...

Thank you,

Beltxarga

PS : I can't seem to achieve a correct indentation for my code in the forum... Is it normal?!