Lisp:如何在列表列表中设置元素?
Lisp: How to set element in list of lists?
我熟悉如何在二维数组中设置元素,可以使用以下语句完成。
(setf (aref array2D 0 0) 3)
但是,我不熟悉如何在列表的列表中设置元素,比如下面的输入:'((1) (2) (2) (1))
。我不能使用 aref
,因为它只适用于数组。
如前所述,而 aref
works on arrays
, elt
works on sequences
可以是:
- 有序的元素集合
- 向量或列表。
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf (elt test-list 2) 'hi)
HI
* test-list
((1) (2) HI (1))
您确实可以使用变量代替固定偏移量:
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf offset 2)
2
* (setf (elt test-list offset) 'hi)
HI
* test-list
((1) (2) HI (1))
要访问列表的第n个元素,有(至少)两个函数:nth
和elt
。参数的顺序不同,nth
仅适用于列表,而 elt
适用于任何序列( 即 列表、向量、字符串...):
(nth 1 '(foo bar baz)) => BAR
(nth 1 #(foo bar baz)) => ERROR
(elt '(foo bar baz) 1) => BAR
(elt #(foo bar baz) 1) => BAR
现在,一般来说,设置一个值(而不是简单地访问它)的方法非常简单,至少对于built-in函数来说,这是几乎总是这样:每当你有某种形式 FORM
从所谓的 place
中检索一些值时,形式 (setf FORM <value>)
会将此元素设置为给定的 <value>
。这适用于 car, cdr, gethash, aref, slot-value, symbol-function
和许多其他函数,以及这些函数的任意组合。
在您的示例中,您有一个列表列表。因此,例如,要修改第三个列表中的“内部整数”:
* (setf test-list '((0) (1) (2) (3))) ; changed the values to have something clearer
((0) (1) (2) (3))
* (car (nth 2 test-list)) ; this accesses the integer in the second list
2
* (setf (car (nth 2 test-list)) 12) ; this modifies it. Notice the syntax
12
* test-list
((0) (1) (12) (3))
附带说明一下,您应该避免修改文字列表(使用引号 '
创建)。如果要修改列表,请在运行时使用 list
函数创建它们。
编辑:
发生的事情是,通过“查看”您提供的表格,setf 知道如何真正找到您想要修改的地方,可能在此过程中使用函数。
如果您查看其他语言,例如 Python,您在用于获取和设置值的语法中也有某种双重性。事实上,如果你有一个列表 L
或一个字典 d
,那么 L[index]
和 d[thing]
将获得相应的元素,而 L[index] = 12
和 d[thing] = "hello"
会修改的。
然而,在Python中,这些访问器使用了一种特殊的语法,即方括号[]
。其他类型的对象使用另一种语法,例如,点符号来访问对象的 slots/attributes,如 my-object.attr
。结果是以下代码在 Python 中无效:
>>> L = [1, 2, 3, 2, 1]
>>> max(L)
3
>>> max(L) = 12
Traceback (most recent call last):
File "<string>", line 9, in __PYTHON_EL_eval
File "/usr/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<string>", line 1
SyntaxError: cannot assign to function call
您必须编写一个 other 函数,例如 setMax(L, val)
,以更改列表的最大值。这意味着你现在必须函数,不再对称。
在 Common Lisp 中,一切(至少在语法上)都是函数调用。这意味着您可以为任何功能定义 访问和修改事物的新方法!作为您可以做什么的(坏)示例:
* (defun my-max (list)
(reduce #'max list))
MY-MAX
* (my-max '(1 2 3 8 4 5))
8
* (defun (setf my-max) (val list)
(do ((cur list (cdr cur))
(cur-max list (if (< (car cur-max) (car cur))
cur
cur-max)))
((endp (cdr cur)) (setf (car cur-max) val))))
(SETF MY-MAX)
* (setf test-list (list 0 4 5 2 3 8 6 3))
(0 4 5 2 3 8 6 3)
* (setf (my-max test-list) 42)
42
* test-list
(0 4 5 2 3 42 6 3)
这样,用于设置和获取列表最大值的语法是相同的(FORM
获取,(setf FORM val)
设置),并自动与其他所有 "setter”。没有明确的 pointers/references 涉及,它只是函数。
我熟悉如何在二维数组中设置元素,可以使用以下语句完成。
(setf (aref array2D 0 0) 3)
但是,我不熟悉如何在列表的列表中设置元素,比如下面的输入:'((1) (2) (2) (1))
。我不能使用 aref
,因为它只适用于数组。
如前所述,而 aref
works on arrays
, elt
works on sequences
可以是:
- 有序的元素集合
- 向量或列表。
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf (elt test-list 2) 'hi)
HI
* test-list
((1) (2) HI (1))
您确实可以使用变量代替固定偏移量:
* (setf test-list '((1) (2) (2) (1)))
((1) (2) (2) (1))
* (setf offset 2)
2
* (setf (elt test-list offset) 'hi)
HI
* test-list
((1) (2) HI (1))
要访问列表的第n个元素,有(至少)两个函数:nth
和elt
。参数的顺序不同,nth
仅适用于列表,而 elt
适用于任何序列( 即 列表、向量、字符串...):
(nth 1 '(foo bar baz)) => BAR
(nth 1 #(foo bar baz)) => ERROR
(elt '(foo bar baz) 1) => BAR
(elt #(foo bar baz) 1) => BAR
现在,一般来说,设置一个值(而不是简单地访问它)的方法非常简单,至少对于built-in函数来说,这是几乎总是这样:每当你有某种形式 FORM
从所谓的 place
中检索一些值时,形式 (setf FORM <value>)
会将此元素设置为给定的 <value>
。这适用于 car, cdr, gethash, aref, slot-value, symbol-function
和许多其他函数,以及这些函数的任意组合。
在您的示例中,您有一个列表列表。因此,例如,要修改第三个列表中的“内部整数”:
* (setf test-list '((0) (1) (2) (3))) ; changed the values to have something clearer
((0) (1) (2) (3))
* (car (nth 2 test-list)) ; this accesses the integer in the second list
2
* (setf (car (nth 2 test-list)) 12) ; this modifies it. Notice the syntax
12
* test-list
((0) (1) (12) (3))
附带说明一下,您应该避免修改文字列表(使用引号 '
创建)。如果要修改列表,请在运行时使用 list
函数创建它们。
编辑: 发生的事情是,通过“查看”您提供的表格,setf 知道如何真正找到您想要修改的地方,可能在此过程中使用函数。
如果您查看其他语言,例如 Python,您在用于获取和设置值的语法中也有某种双重性。事实上,如果你有一个列表 L
或一个字典 d
,那么 L[index]
和 d[thing]
将获得相应的元素,而 L[index] = 12
和 d[thing] = "hello"
会修改的。
然而,在Python中,这些访问器使用了一种特殊的语法,即方括号[]
。其他类型的对象使用另一种语法,例如,点符号来访问对象的 slots/attributes,如 my-object.attr
。结果是以下代码在 Python 中无效:
>>> L = [1, 2, 3, 2, 1]
>>> max(L)
3
>>> max(L) = 12
Traceback (most recent call last):
File "<string>", line 9, in __PYTHON_EL_eval
File "/usr/lib/python3.8/ast.py", line 47, in parse
return compile(source, filename, mode, flags,
File "<string>", line 1
SyntaxError: cannot assign to function call
您必须编写一个 other 函数,例如 setMax(L, val)
,以更改列表的最大值。这意味着你现在必须函数,不再对称。
在 Common Lisp 中,一切(至少在语法上)都是函数调用。这意味着您可以为任何功能定义 访问和修改事物的新方法!作为您可以做什么的(坏)示例:
* (defun my-max (list)
(reduce #'max list))
MY-MAX
* (my-max '(1 2 3 8 4 5))
8
* (defun (setf my-max) (val list)
(do ((cur list (cdr cur))
(cur-max list (if (< (car cur-max) (car cur))
cur
cur-max)))
((endp (cdr cur)) (setf (car cur-max) val))))
(SETF MY-MAX)
* (setf test-list (list 0 4 5 2 3 8 6 3))
(0 4 5 2 3 8 6 3)
* (setf (my-max test-list) 42)
42
* test-list
(0 4 5 2 3 42 6 3)
这样,用于设置和获取列表最大值的语法是相同的(FORM
获取,(setf FORM val)
设置),并自动与其他所有 "setter”。没有明确的 pointers/references 涉及,它只是函数。