Elisp - 遍历一个关联列表

29

在Emacs Lisp中,循环遍历一个alist并对每个pair做一些处理,最好的方法是什么?我想一个宏不难写,只是想知道这是否已经内置了。除下面所示的方法外,是否有更优雅的方式?

(setq my-list '((a . 1)
                (b . 2)
                (c . 3)))

(loop for key in (mapcar 'car my-list)
      for value in (mapcar 'cdr my-list)
      collect (cons value key))

;; Returns this
((1 . a)
 (2 . b)
 (3 . c))
4个回答

31

cl-loopcl-macs.el 中的支持可以像 CL 一样进行解构:

(cl-loop for (key . value) in my-list
      collect (cons value key))

6
由于cl已被弃用,现代的替代方案是使用具有完全相同功能的cl-loop宏,该宏位于cl-lib库中。该库已内置于较新版本的emacs中,并且可以从GNU ELPA获取向后兼容的软件包。 - sanityinc
2
这里的“collect”是什么意思? - Benilda Key

19

不清楚您想要做什么 - 问题非常泛泛。有许多方法可以循环遍历alist并对其条目的某些或所有内容进行操作。您展示了一种方法。还要看看while和特别是dolist。 这是使用dolist的示例:

    (let ((res ()))
     (dolist (x my-list)
       (push (cons (cdr x) (car x)) res))
     (nreverse res))

(也许有比您的示例更好的使用loop的方法 - 不需要构建三个列表(两个mapcar + loop),例如。)


19

不用 loop 进行这个操作的另一种方法是使用 mapcar 和 lambda。我认为这并不比使用 Common Lisp 更优雅,但它更符合 elisp 的惯用法:

(mapcar (lambda (element)
      (let ((key (car element))
            (value (cdr element)))
      (cons value key)))
      '((1 . a) (2 . b)))

我更喜欢这个答案,因为它没有使用 cl - kindahero
1
@kindahero 你知道loop是一个cl宏吗?这很正常。 - event_jr
8
请注意,字节编译会警告在顶层使用mapcar进行副作用操作,即忽略其返回值。对于简单的迭代,建议使用dolist - sanityinc
@sanityinc 这应该是一个答案。 - clacke

7

dash.el 提供了许多类似于map的列表操作函数。那些接受函数作为参数的函数也有指示代词版本。这使得代码更加简洁函数式dash.el 函数以破折号开头,因此得名,而指示代词版本则以两个破折号开头。所以ataylor的变体看起来会更好:

(--map (cons (cdr it) (car it)) '((1 . a) (2 . b))) ; ((a . 1) (b . 2))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接