Let say I have this list.
'((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1)))
How do I get this?
'((tag1 (name name3 name5))
(tag2 (name2 name5))
(tag3 (name4)))
This is for my blog: Tagged view (experimental)
1 Like
I think this could do the trick:
(progn
(setq articles '((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1)))
the-tags '()
tags-list '()
tags-listp '())
(mapcar (lambda (entry)
(let* ((title (car entry))
(tags (cadr entry)))
(message "Processing %S" entry)
(message " title %S" title)
(message " tags %S" tags)
(mapcar (lambda (tag)
(add-to-list 'the-tags tag :append)
(let ((tag-list (plist-get tags-listp tag)))
(message " tag-list(%S) %S" tag tags-listp)
(setq tags-listp (plist-put tags-listp tag (append `(,title) tag-list)))))
tags)))
articles)
the-tags
(mapcar
(lambda (tag)
(add-to-list 'tags-list `(,tag ,(plist-get tags-listp tag))))
the-tags)
tags-list)
Most surely it is not the most efficient way to code this, but it works.
1 Like
This is what I wrote Taxy for: GitHub - alphapapa/taxy.el: Programmable taxonomical hierarchies for arbitrary objects
Here’s an example of doing it with your sample code:
(let* ((articles '((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1))))
(tags (delete-dups
(flatten-list (mapcar #'cadr articles))))
(taxy (make-taxy
:name "Blog articles"
:taxys (mapcar (lambda (tag)
(make-taxy :name (symbol-name tag)
:predicate (lambda (article)
(member tag (cadr article)))
:then #'identity))
tags))))
(setf taxy (thread-last taxy
taxy-emptied
(taxy-fill articles))
(taxy-items taxy) nil)
(taxy-plain taxy))
That produces:
("Blog articles"
(("tag1" ((name5 (tag2 tag1))
(name3 (tag1))
(name (tag1))))
("tag2" ((name5 (tag2 tag1))
(name2 (tag2))))
("tag3" ((name4 (tag3))))))
3 Likes
cryptk
April 5, 2024, 12:59am
4
My attempt:
(let* ((data '((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1)))))
(mapcar (lambda (tag)
`(,tag ,(delete nil
(mapcar (lambda (item)
(when (member tag (cadr item))
(car item)))
data))))
(delete-dups (flatten-tree (mapcar #'cdr data)))))
2 Likes
This made sense to me so I adopted it.
1 Like
I think you can use a hashtable or plist for the second list (the one you want to make) then you don’t have to worry about duplicate keys. and will have one less mapcar!
with plist:
(let ((l '((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1))))
(pl (list)))
(mapcar (lambda (item)
(mapcar (lambda (tag)
(setq pl (plist-put pl tag (append (list (car item)) (plist-get pl tag)))))
(cadr item)))
l)
pl
)
but personally I’d prefer a hashtable:
(let ((data '((name (tag1))
(name2 (tag2))
(name3 (tag1))
(name4 (tag3))
(name5 (tag2 tag1))))
(table (make-hash-table :test 'equal)))
(mapcar (lambda (item)
(mapcar (lambda (tag)
(puthash tag (append (list (car item)) (gethash tag table))
table))
(cadr item)))
data)
table
)
I think you can use a hashtable or plist for the second list (the one you
want to make) then you don’t have to worry about duplicate keys. and will
have one less mapcar!
I will make sure to take a look at it, the current solutions works fine
but it has 2 mapcars as you say.