【问题标题】:Idiomatic way in Emacs Lisp to visit each cons cell in a list?Emacs Lisp 中访问列表中每个 cons 单元格的惯用方式?
【发布时间】:2021-12-30 00:11:55
【问题描述】:

我想访问列表中的所有cons 单元格并对它们执行一些操作(包括setcar 之类的东西)。有没有一种惯用的方法?

我想,我可以做这样的事情

(progn
  (setq a (list 1 2 3 4 5 6))
  (setq okay a)
  (while okay
    (if (eq (car okay) 3)
        (setcar okay 22))
    (setq okay (cdr okay))))

(例如,if 表达式是我的“应用程序逻辑”。)

但是,如果有更简洁的方法,我很想听听。

【问题讨论】:

标签: emacs lisp


【解决方案1】:
(setq a (mapcar (lambda (x) (if (equal x 3) 22 x)) a))

这会将变量 a 的值设置为将 a 的任何成员从 3 更改为 22 的结果。

根据您是否知道所有列表成员都是数字(使用 =)或者您知道它们是数字还是你想测试对象是否相等,(使用eql),或者你不知道它们可能是什么(使用equal)。

您没有表示需要修改列表结构 (setcar)。看来您只关心a 是否是我所描述的列表。

【讨论】:

  • 德鲁,谢谢。事实上,我确实想要setcar
  • 在这种情况下,按照@ignis volens 的建议执行 - 使用cl-mapl。 (您可以使用 setcarcl-rplaca - 同样的东西。)
【解决方案2】:

如果您想改变列表中的汽车,那么在最近的 emacsen 中,您可能想要的是 cl-mapl,它将一个函数映射到列表的连续尾部。这本质上是 Common Lisp 的 mapl 函数:CL 有

  • maplist 将函数映射到尾部并返回函数值的新列表,因此 (maplist (lambda (e) e) '(1 2 3))((1 2 3) (2 3) (3))
  • mapl 类似于 maplist 但返回原始列表。

elisp(由一些现在的标准库提供)现在同时具有 cl-maplcl-maplist

所以:

> (let ((y (list 1 2 3 4 5 6 7)))
    (cl-mapl (lambda (tail)
               (rplaca tail 0))
             y)
    y)
(0 0 0 0 0 0 0)

> (let ((y (list 1 2 3 4 5 6 7)))
    (cl-mapl (lambda (tail)
               (rplaca tail (if (cdr tail) (cadr tail) 'fish)))
             y)
    y)
(2 3 4 5 6 7 fish)

(在这两种情况下,您都不需要确保返回 y:我这样做只是为了表明 y 正在被破坏性地修改。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-12
    • 1970-01-01
    • 2012-01-26
    • 2011-10-05
    • 1970-01-01
    • 2010-11-21
    • 1970-01-01
    相关资源
    最近更新 更多