Emacs -- 如何用 let-bound 变量替换列表中的第 n 个元素



我没有找到任何示例来替换列表的nth元素,而无需首先用函数add-to-ordered-list添加每个元素(一个接一个( - 例如,(add-to-ordered-list 'the-list 'a 1) 。 这需要随后删除元素 - 例如,(delq a the-list) 。 该过程的第三步是添加新元素 - 例如,(add-to-ordered-list 'the-list "HELLO-WORLD!" 1) 。 由于以下名为 variable-list-example 的函数使用 26 个元素,因此我正在寻找一种更好的方法,而不是首先添加所有 26 个元素(一个接一个(来基本上为每个元素分配一个位置编号。 该函数add-to-ordered-list使用的数字赋值与标准nth元素方法不同一位数,其中第一个元素的值为 0,而add-to-ordered-list对第一个元素使用1的值。 以下是add-to-ordered-list文档的链接: http://www.gnu.org/software/emacs/manual/html_node/elisp/List-Variables.html

此外,在列表开头使用组合'(似乎可以防止在列表中使用 let-bound 变量 - 例如,let bound变量在列表中显示为my-variable而不是HELLO-WORLD!。 我发现的唯一解决方法是上面提到的使用 add-to-ordered-list 的示例——这是一个漫长的三步过程(即,在开始时逐个添加每个元素(。

为了解决这两个问题,我正在寻找一些帮助,请将the-list17th元素(即字母 r (替换为my-variable(HELLO-WORLD!(。


(defun variable-list-example ()
(interactive)
  (let* (
      (my-variable "HELLO-WORLD!")
      (the-list '(a b c d e f g h i j k l m n o p q r s t u v w x y z)))
    ;; replace the 17th element of `the-list` with `my-variable`
    (message "Presto -- this is your new list:  %s" the-list)
  ))

目录

'(a b c d e f g h i j k l m n o p q r s t u v w x y z)

第 N 个元素 -- 备忘单/图例

element 0:   a
element 1:   b
element 2:   c
element 3:   d
element 4:   e
element 5:   f
element 6:   g
element 7:   h
element 8:   i
element 9:   j
element 10:  k
element 11:  l
element 12:  m
element 13:  n
element 14:  o
element 15:  p
element 16:  q
element 17:  r
element 18:  s
element 19:  t
element 20:  u
element 21:  v
element 22:  w
element 23:  x
element 24:  y
element 25:  z

你需要使用 setcarnthcdr

(setcar (nthcdr 17 the-list) my-variable)

更常见的类似 Lisp 的方法是使用广义变量:

(setf (nth 17 the-list) my-variable)

Emacs 有一个广义变量的概念,它本质上是允许你用 setf 来改变任意的存储位置。 例如,您可以更改列表的位置carcdr位置,包括 nth 返回的car。 因此,以下代码

(let ((foo 10)
      (l '(1 2 3 4 5 6 7 8)))
  (setf (nth 4 l) foo)
  l)

将返回列表(1 2 3 4 10 6 7 8)

要将变量直接放入带引号的列表中,必须更改引号的类型。 标准引号'禁止引用表达式内的任何计算

但是,特殊的反引号允许您计算带引号的表达式内的表达式:

(let* ((foo 10)
      (l `(1 2 3 4 5 ,foo 7 foo)))
  l)
前导逗号

标记后续表达式以供评估,而不带前导逗号的表达式将按字面意思获取。 在上面的示例中,将评估列表中第一次出现的foo,因此替换为10,而第二次出现最终出现在列表中。

添加一个专门关于add-to-ordered-list的后期答案,因为我认为人们对它的作用和工作方式存在混淆。

add-to-ordered-list允许您为单个列表元素指定(记录(特定顺序。

但该列表也可以包含没有为其记录特定顺序的元素。 这些元素始终放在列表的末尾,在所有具有特定记录顺序的元素之后。

如果要替换具有记录顺序的元素,则需要将其从列表中删除并添加其替换(这是您猜测的(。

(add-to-ordered-list 'the-list 'a 1) ; Records order 1 for element (symbol) a. 
(delq a the-list) ; Removes a from the list.
(add-to-ordered-list 'the-list 'HELLO 1) ; Records order 1 for element (symbol) HELLO.

要补充一些内容,以帮助澄清一点:

  1. 您不能使用字符串元素,例如 "HELLO" ,因为记录元素的顺序要求它们可以使用 eq(而不是 equalstring= (进行区分。

  2. 您可以从元素中删除记录的顺序,而不是从列表中删除该元素。 如果这样做,该元素将保留在列表中,但在具有记录订单的任何元素之后移动。 这不是你想要的(你想替换它(,但要知道这是可能的。 为此,您可以使用元素调用add-to-ordered-list,但没有ORDERED值(或nil值(。

  3. 为元素记录的订单不需要为所有元素指定(见上文(,也不必是连续的。 重要的是它们可以在数字上进行比较,因此它们的元素可以排序。 例如,您可以添加元素 abc' to an empty list, recording orders of 13, 42, and 6 for them, respectively. The result is the list (c a b(',因为 6 <12 <42。

  4. 您甚至可以为多个列表元素记录相同的顺序,在这种情况下,这些元素在列表中是连续的,但它们之间的顺序并不重要。 您可以将记录的订单视为桶或分数。 得分为 3 的所有元素都显示在列表中,然后出现在得分为 7 的所有元素之前,得分为 3(或 7(的元素是连续的。

另请参阅此 emacs.SE 问题。

最新更新