我想改变这些列表:
(setq terms '((("name" . "t1c1")
("taxonomy" . "category"))
(("name" . "t1c2")
("taxonomy" . "category"))
(("name" . "t1k1")
("taxonomy" . "post_tag"))
(("name" . "t1k2")
("taxonomy" . "post_tag"))
(("name" . "t1k3")
("taxonomy" . "post_tag"))))
进入另一个列表清单:
(("category" "t1c1" "t1c2")
("post_tag" "t1k1" "t1k2" "t1k3"))
我想出了:
(reduce
'(lambda (lists term)
(let* ((name (cdr (assoc "name" term)))
(taxonomy (cdr (assoc "taxonomy" term)))
(existing (assoc taxonomy lists)))
(if existing
(progn
(setcdr existing (sort (cons name (cdr existing)) 'string<)))
(push (list taxonomy name) lists)))
lists)
terms
:initial-value nil)
看起来不太优雅---使用let *和if语句看起来都像潜在的代码气味。
我很感激任何更好的方法在elisp中做到这一点的例子 - 更好的意思是更纯粹的功能,更好地使用内置函数来表示某些操作等。
哦,我希望对得到的alists的内容进行排序---这使我更容易测试输出。
答案 0 :(得分:2)
最让人想到的是使用(loop ...)
宏。有人可能会认为它不够灵敏,但我认为它的简洁性和表现力胜过纯洁:
(loop
with result = '()
for term in terms
for name = (aget term "name")
for taxonomy = (aget term "taxonomy")
do (aput 'result taxonomy
(sort (cons name (aget result taxonomy)) 'string<))
finally return result)
答案 1 :(得分:1)
我很感激有任何更好的方法可以做到这一点 elisp ---哪里更好可能意味着更纯粹的功能,更好地利用 内置函数来表示某些操作等。
也许是这样的(假设加载了cl-lib
):
(cl-flet ((step (lists term)
(let ((name (aget term "name"))
(taxonomy (aget term "taxonomy")))
(cl-acons taxonomy
(sort (cons name (aget lists taxonomy)) #'string<)
(cl-remove taxonomy lists :key #'car :test #'equal)))))
(reduce #'step dhl-terms :initial-value nil))
它的效率低于你的解决方案,因为“更纯粹的功能”也意味着不使用setcdr
- 它将包含新条目,并再次传递以删除旧条目。