3

I'm probably missing something simple here but... I've got a list of alists parsed from JSON using json-parse-string. The list of alists is like the following (details omitted for brevity):

( ((id . 1) (url . "http://gnu.org") (description . "GNU Operating System"))
  ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation")) ... )

I'm trying to retrieve an alist from the list by the value associated to id in the alist.

E.g. (function 2 list) would return ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation"))

Obviously I could while or cl-loop over the list to find this out, but what is more a Lispy way of doing this?

3 Answers 3

4

If the structure/sequence is very dependable then you might just do this:

(require 'cl-lib)

(cl-find 2 list :key #'cdar)
;; or
(car (cl-member 2 list :key #'cdar))

More robustly, you'd use one of the alist functions to obtain the correct value to test against.

(cl-find 2 list :key (apply-partially #'alist-get 'id))
=> ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation"))

(cl-find "http://fsf.org" list
         :key (apply-partially #'alist-get 'url)
         :test #'string=)
=> ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation"))
1
  • Thanks for the answers guys. I find this answer the most elegant for my use.
    – Inops
    Commented Nov 25, 2020 at 21:09
3

I'd probably do something like this:

(setq toto '(((id . 1)
              (url . "http://gnu.org")
              (description . "GNU Operating System"))
             ((id . 2)
              (url . "http://fsf.org")
              (description . "Free Software Foundation"))))

(defun foo (val lst)
  "..."
  (let ((al  (cl-member val lst :key `(lambda (xx) (cdr (rassoc ',val xx))))))
    (car al)))

(foo 2 toto) ; => ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation"))

Or if you have lexical-binding turned on (i.e., non-nil), then just use this for :key - no need for the backquoting to insert the value of val, which would otherwise be a free variable:

(lambda (xx) (cdr (rassoc val xx)))
2

To find a item from a list, I will probably use seq-find

(seq-find
 (lambda (alist)
   (= (alist-get 'id alist) 1))
 '(((id . 1) (url . "http://gnu.org") (description . "GNU Operating System")) 
   ((id . 2) (url . "http://fsf.org") (description . "Free Software Foundation"))))
;; => ((id . 1) (url . "http://gnu.org") (description . "GNU Operating System"))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.