(defun collect-alist-from-tree (tree key)
(let ((collection))
(defun look (tree)
(cond-let*
([item (and (json-alist-p tree)
(assq key tree))]
(push item collection))
((proper-list-p tree)
(mapcar #'look tree)))))
collection)

I have a very nested tree, and I want to get a list of all the places there is a alist with key.

Is there a better way to do this?

#emacslisp #emacs

@tusharhero immediately i notice that you should use cl-labels/cl-flet instead of a defun since defun is global

@zardoz03 initially I had a very specific version working (no generalization).

Now for some reason, as soon as I generalized it, it's broken.

@tusharhero

i think i have it working nwo

@zardoz03 THANK YOU SO MUCH! :D

@zardoz03

What I ended up with

(defun collect-alist-from-tree (tree key)
(let (collection)
(named-let look ((tree tree))
(if-let* ((item (and (json-alist-p tree)
(assq key tree))))
(push item collection)
(when (proper-list-p tree)
(mapcar #'look tree))))
collection))

#emacs #emacslisp

@tusharhero didnt think named-let could pass its name as a hash quote, looks good!!
@zardoz03 I am very satisfied with how simple it is :D

@zardoz03

(mapcar (lambda (video)
(let-alist video
`(
:title ,(collect-alist-from-tree .title 'text)
:owner ,(collect-alist-from-tree .ownerText 'text))) )
(collect-alist-from-tree parsed-responses 'videoRenderer))

((:title ("CMMC & Subcontractors, the Real Requirements") :owner
("Summit 7"))
(:title
("Happy Easter 2026 | Growth & Prosperity | SMIFS Limited & Mackertich One")
:owner ("SMIFS LIMITED"))
(:title ("We should NOT have drank that....") :owner ("SammyC_tv"))
(:title ("Your SaaS Moat Is Probably Just Friction") :owner
("Phil Smy"))
(:title
("#StayPositive #ProtectYourEnergy #Mindset #Growth #SelfAwareness")
:owner ("SAMS Real Estate Brokerage"))

it is very satisfying to have such a nice way to do this.

@zardoz03

What I have now:

(defun insidious--collect-values-by-key (tree key)
"Collect all values in TREE with KEY.

This means:
All alist value with KEY.
And all cons pairs with KEY as car.

Example:

(setq foobar '(((foo . bar1))(foo bar2)))
(insidious--collect-values-by-key foobar 'foo)

=> (bar1 bar2)"
(let (collection)
(named-let look ((tree tree))
(cond* ((bind* (element (and (json-alist-p tree)
(assq key tree)))))
(element (push (cdr element) collection))
((and (consp tree)
(eq key
(car tree)))
(push (cadr tree) collection))
((proper-list-p tree)
(mapc #'look tree))))
(nreverse collection)))

@tusharhero what do the cond* and bind* do now, i havent seen this before

@zardoz03 A pretty new construct, I had to read the docstring multiple times.

cond* is basically cond in this context, except that the bind* form is like let.