我想成为一个好的错误并避免使用“++”。我需要在列表的末尾添加一个元组而不创建嵌套列表(希望不必向后构建它并反转它)。给定元组T并列出L0和L1:
当我使用 [T | L0] 时,我得到 [元组,列表0] 。
但是当我使用 [L0 | T] 时,我会得到嵌套列表 [[list0] | tuple] 。同样, [L0 | L1] 会返回 [[list0] | list1] 。
删除外部列表括号 L0 | [T] 会产生语法错误。
为什么是“|”不对称?有没有办法用“|”做我想做的事?
答案 0 :(得分:20)
|
不是“对称的”,因为非空列表有头部和尾部,其中头部是单个项目,尾部是另一个列表。表达式[foo | bar]
foo
表示列表的头部,bar
表示尾部。如果尾部不是正确的列表,则结果也不是正确的列表。如果head是一个列表,结果将只是一个列表,该列表作为其第一个元素。
在少于O(n)的时间内无法在链表的末尾追加。这就是为什么使用++
通常被避免的原因。如果在列表的末尾附加了特殊的语法,那么它仍然需要花费O(n)时间并且使用该语法不会比使用++
更能让你成为一个“好的错误”。
如果你想避免每次插入的O(n)成本,你需要先插入然后反转。如果您愿意支付费用,也可以使用++
。
关于列表如何工作的更多细节:
[ x | y ]
是一种称为利弊细胞的东西。在C语言中,它基本上是一个有两个成员的结构。正确的列表是空列表([]
)或第二个成员是正确列表的cons单元格(在这种情况下,第一个成员称为其头部,第二个成员称为其尾部)。
因此,当您编写[1, 2, 3]
时,会创建以下缺点:[1 | [2 | [3 | []]]]
。即该列表表示为cons单元,其第一个成员(其头部)为1,第二个成员(尾部)为另一个cons单元。另一个cons细胞有2个作为其头部,而另一个cons细胞作为它的尾部。该单元格的头部为3,尾部为空列表。
遍历这样的列表是通过首先作用于列表的头部然后调用列表尾部的遍历函数来递归完成的。
现在,如果您想要将一个项目添加到该列表中,这很容易:您只需创建另一个缺点单元格,其头部是新项目,其尾部是旧列表。
然后追加一个项目要贵得多,因为创建一个cons单元格是不够的。你必须创建一个与旧的列表相同的列表,除了最后一个cons单元格的尾部必须是一个新的cons单元格,其头部是新元素,其尾部是空列表。所以你不能在不经过整个列表的情况下附加到列表中,即O(n)。