【问题标题】:Process list modifying elements in elispelisp中的进程列表修改元素
【发布时间】:2016-03-24 14:15:40
【问题描述】:

我是 elisp 的新手,并且仍在学习如何将我用 C 或 Perl 编写的东西转换为相应的 elisp 代码。在特定情况下,我需要处理一个列表元素来修改这些。我考虑过dolist,但与Perl 的foreach 不同,我无法修改原始列表值。我想出了以下代码,但它似乎过于复杂(至少对我来说它看起来不太可读):

(setq x '("a" "b" "c"))
(let ((p x))
  (while (car p)
    (setcar p (concat ">" (car p)))
    (setq p (cdr p))))

有没有更好的方法来达到同样的效果?

【问题讨论】:

    标签: list emacs foreach elisp


    【解决方案1】:

    嗯……因为我是法国人,我不确定我能清楚地解释我的意思……

    “修改原始列表值”有歧义,如“修改列表元素”。

    Drew,在您的示例中,您演示了使用dolist,您可以枚举列表,并且对于列表中的每个项目,您可以应用一个函数(如setcar),这将改变一些东西里面这个项目。

    好的。

    但是,对于dolist,您不能将列表中的每个项目替换为另一个项目,例如将p 替换为(concat ">" p)

    在您的示例中,列表(2 2)eq 到列表(3 2)

    所以你可以说bar 仍然指向同一个cons 单元格,并且bar 的每个元素也仍然指向同一个cons 单元格。

    我们可以说您更改/修改了第一个元素(在法语中,“vous avez changé lepremier élément”),但您不能说您替换了第一个元素(“vous avez changé de Premier élément”)。

    Aamof,有趣的是,在法语中,只有一个不同的字母!

    无论如何,dolist 做不到,但do 可以做到:

    (do ((p x (cdr p))) ((null p) x) (setcar p (concat ">" (car p))))

    【讨论】:

      【解决方案2】:

      我建议您尝试考虑如何在不修改列表的情况下 做您想做的事情。 IE。相反,返回另一个列表。例如:

      (let ((newlist
             (mapcar (lambda (p) (concat ">" p))
                     x)))
        ...use newlist...)
      

      【讨论】:

      • 在这种情况下,我绝对不再需要原始列表,并且想避免复制...将mapcar结果重新分配给原始列表似乎是浪费列表,但我可以看到它更具可读性。
      【解决方案3】:

      dolist 阻止您修改列表元素是正确的。您在dolist 中声明的局部变量被绑定到列表的连续元素 - 实际元素,而不是它们的副本。您可以随心所欲地修改这些单独的元素。

      您可能对可能包含这些元素的原始列表(或任何列表)感到困惑。

      例如:

      (defun foo (xs)
        (dolist (x xs) (setcar x 3)))
      
      (setq bar '((2 2) (4 4 4) (6 6 6)))
      
      (foo bar)
      

      C-h v bar 向您显示列表 bar 确实已通过 dolist 代码更改了其每个元素:

      bar's value is 
      ((3 2)
       (3 4 4)
       (3 6 6))
      

      bar 仍然指向同一个 cons 单元格,但列表中的每个元素都将其 car 设置为 3。


      更新回复@duthen:

      这不是关于“bar [仍然指向]同一个 cons 单元格的每个元素”。

      这是关于列表修改的。您想要替换(或以其他方式更改)特定列表中的实际元素,或者您不想。如果你这样做了,你当然可以使用dolist 来做到这一点。元素不必是 conses。

      但如果您只想替换特定列表元素,这意味着您不想修改该列表的顶级列表结构。否则,您将构建一个新列表,而不是仅修改现有列表的元素。

      dolist 本身不会修改其列表参数的顶级列表结构。但它根本不会阻止您更改该列表中的 元素。这包括更改 他们的 列表结构,如果它们本身是列表(conses),如我上面的示例所示。 dolist 本身并不是树操作。

      这是另一个示例,其中列表元素是字符串。同样,元素本身被修改 - 替换,但包含它们的列表是相同的(这个列表只有顶级列表结构)。

      (defun foo (xs)
        (dolist (x xs) (setf (aref x 0) ?$)))
      
      (setq bar '("abc" "def" "ghij"))
      
      (foo bar)
      

      bar 的列表值确实发生了变化。它的元素是不一样的——它们被不同的值所取代。列表的 cons 单元格是相同的 cons 单元格,但它们的汽车没有相同的值。

      dolist 只允许您访问列表中的单个元素。它不会让您访问构成列表本身的顶级 cons。您不能使用dolist 将元素"abc" 替换为元素42,因为您不能修改前一个对象以赋予后者。如果您想进行这样的替换,那么您需要 访问列表的 conses 而不仅仅是列表中的 elements。元素只是构成列表的顶级 conses 的汽车。

      问题提出的问题是这样的:“处理列表元素以修改这些”。正如这些示例所示,使用dolist 完全可以做到这一点。没有办法修改"abc"给你42。如果你想要这种元素替换,那么你需要修改列表 conses。

      如果问题的意思不同,那么就不清楚了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-02
        • 2017-12-12
        • 1970-01-01
        • 1970-01-01
        • 2011-09-17
        • 2019-01-07
        相关资源
        最近更新 更多