Page 1 of 1

Find a value in an association list

Posted: Sun Jun 29, 2014 10:25 am
by Beltxarga
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

Code: Select all

((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:

Code: Select all

(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,

Code: Select all

(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:

Code: Select all

[((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

Re: Find a value in an association list

Posted: Mon Jun 30, 2014 8:32 am
by edgar-rft

Code: Select all

(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

Posted: Tue Jul 01, 2014 1:48 pm
by Beltxarga
edgar-rft wrote:

Code: Select all

(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:

Code: Select all

(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 :

Code: Select all

   (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:

Code: Select all

(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?!