(emacs) lisp: search anything in a ((nested) list)

Viewed 2634

I need to locate a particular value that can be buried into a deeply nested list, and never at the same place. Or even the same depth ; Here is one form of the list:

(setq my-list '(((partnum . 1) (type (TEXT . plain)) (body (charset UTF-8))
                 (disposition nil) (transfer-encoding QUOTED-PRINTABLE))
                ((partnum . 2) (type (TEXT . html)) (body (charset UTF-8))
                 (disposition nil) (transfer-encoding QUOTED-PRINTABLE)))) 

Now I need to retrieve the value of "charset" ; The first one if any. In this very configuration, it's easy:

(car (cdr (cadr (third (car my-list)))))
   => UTF-8

But this is when I know exactly where the "body" cell is.

I tried to use mapcar recursively like this :

(defun search-rec (list)
  (mapcar
     (lambda (x)
       (if (listp x)
           (search-rec x)
         (message "OY %s" x)))
     list))

but every time, I get the error (wrong-type-argument listp 1) when the recursion hits the first atom of the first cons cell. I guess my question really is what it is :

How can I search in a list?

EDIT Now the list looks like this, "charset" is still in (body) (told you that was about the only constant thing) and it's no longer found :(

(setq my-list '(((partnum . 1)
                (1.1 (type (TEXT . plain)) (body (charset UTF-8))
                     (disposition nil) (transfer-encoding 7BIT))
                (1.2 (type (TEXT . html)) (body (charset UTF-8))
                     (disposition nil) (transfer-encoding 7BIT))
                (type . alternative) (body (boundary e89a8fb2067eba300404c63c5f7f))
                (disposition nil) (transfer-encoding nil))
               ((partnum . 1.1) (type (TEXT . plain)) (body (charset UTF-8))
                (disposition nil) (transfer-encoding 7BIT))
               ((partnum . 1.2) (type (TEXT . html)) (body (charset UTF-8))
                (disposition nil) (transfer-encoding 7BIT))
               ((partnum . 2) (type (IMAGE . x-xpixmap)) (body (name ladybug.xpm))
                (disposition nil) (transfer-encoding BASE64))))

EDIT here is some more IRL example:

    (setq my-list haystack-list)
    (setq my-needle (tree-assoc 'charset my-list))
    (message "
-------------\n
- my-list: %s\n
- my-needle: %s\n
-------------\n" my-list my-needle)

Produces:


  • my-list: ((TEXT plain (charset UTF-8) nil nil 7BIT 260 18 nil nil nil) (TEXT html (charset UTF-8) nil nil QUOTED-PRINTABLE 738 17 nil nil nil) alternative (boundary e89a8fb1f8061a6be404c70a24a0) nil nil)

  • my-needle: nil


When on the other hand:

(tree-assoc 'charset '((TEXT plain (charset UTF-8) nil nil 7BIT 260 18 nil nil nil)
(TEXT html (charset UTF-8) nil nil QUOTED-PRINTABLE 738 17 nil nil nil) 
alternative (boundary e89a8fb1f8061a6be404c70a24a0) nil nil))
  =>(charset UTF-8)

So really, I don't know what's going on here : One could argue "what is this haystack-list and where does it come from?" But is it relevant ? I'm working on a copy (my-list) of this haystack-list so what gives those different results ? The quoting of the list ? Guys, I'm really lost

NB (This behaviour (Works in a direct eval, but not in a defun/let production situation) occurred with all the solution given)

EDIT: I ended up extracting the first list found, and then extracting (not searching) elements from that list. I proved faster ; Of course this is when you can say "my element is always in the fist list found) ; thanks to everybody, I learned a lot through all this.

4 Answers
Related