Emacs 基于值将Alist列表转换为不同的Alist列表

Emacs 基于值将Alist列表转换为不同的Alist列表,emacs,lisp,elisp,reduce,Emacs,Lisp,Elisp,Reduce,我要转换此Alist列表: (setq terms '((("name" . "t1c1") ("taxonomy" . "category")) (("name" . "t1c2") ("taxonomy" . "category")) (("name" . "t1k1") ("taxonomy" . "post_tag"))

我要转换此Alist列表:

(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"))
以下是其他列表中的列表:

(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)
(减少
'(lambda(列出术语)
(让*((名称(cdr)(关联“名称”术语)))
(分类法(cdr(联合“分类法”术语)))
(现有(assoc分类列表)))
(如有)
(项目

(setcdr-existing(sort(cons-name(cdr-existing))string想到的最优雅的方法是使用
(loop…
宏。有人可能会说它不够elisp-y,但我认为它的简洁性和表达性胜过纯粹性:

(循环
结果为“”()
用术语
对于名称=(aget术语“名称”)
对于分类法=(aget术语“分类法”)
do(aput)结果分类法
(排序(cons名称(aget结果分类))'字符串
如果有更好的方法,我将不胜感激
更好可能意味着更纯粹的功能,更好地使用
表示某些操作等的内置函数

可能是这样的(假设加载了
cl-lib
):

(cl flet)((步骤(列出术语)
(名称(aget术语“名称”))
(分类学(aget术语“分类学”))
(cl)乌头分类学

(排序(cons名称(aget列出分类法))#'stringYeah,不使用setcdr会缩短它——不需要测试是否存在——但也会降低效率。是的。如果您关心性能,您可以通过考虑结果列表的前面,删除不需要的条目作为最后一步,使用
cl删除重复项
:从t
。(之后也可以进行排序。)但这是否真的有区别取决于您的用例。事实上,在回顾这两个答案时,我刚刚意识到:因为我只想得到一个列表,我可以查询我预先知道的两个键,我可以将更新的项放在列表的前面,我的查询只会看到最新的,这是每个列表最完整的版本。是的,这是使用alists的优点之一。(它与示例输出不匹配,所以我照原样做了,并将其与原始代码保持相对接近。)顺便说一句:正如您在对Immerr的回答的评论中所说,我不知道
aget
&c已经过时了。您仍然可以通过使用
assoc default
而不用它的可选参数来节省一些字符。因此,我对lisp还是相当陌生的,所以我可能有点离谱——但看起来您实际上刚刚使用循环实现了reduce,并且精确性实际上来自于使用aput/aget,在这里,我在做我的alist操作时没有使用assoc.el(从Emacs 24.3开始,它就被宣布为过时)。此外,我还很新,可以lisp说,在没有大量paren的情况下做它似乎是错误的。;)这很好:)每个人都觉得lisps有其特殊之处,我个人喜欢——可以说是——函数式和命令式代码之间的完美平衡。使代码本身成为AST的括号只是顶部的樱桃,允许使用我在使用python和C/C++时非常怀念的paredit。至于
assoc.el
弃用,是的,我应该怀疑这样的事情:)