如何在erlang中连接列表而不创建嵌套列表?
我正在努力成为一名优秀的管理者并避免使用“++”。我需要将一个元组添加到列表的末尾,而不创建嵌套列表(并且希望不必向后构建它并反转它)。给定元组 T 和列表 L0 和 L1:
当我使用 [T|L0] 时,我得到 [tuple,list0]。
但是当我使用[L0|T]时,我得到嵌套列表[[list0]|tuple]。同样,[L0|L1] 返回[[list0]|list1]。
删除外部列表括号 L0|[T] 会产生语法错误。
为什么是“|”不对称?有没有办法使用“|”来做我想做的事情?
I'm trying to be a good erlanger and avoid "++". I need to add a tuple to the end of a list without creating a nested list (and hopefully without having to build it backwards and reverse it). Given tuple T and lists L0 and L1:
When I use [T|L0] I get [tuple,list0].
But when I use [L0|T], I get nested list [[list0]|tuple]. Similarly, [L0|L1] returns [[list0]|list1].
Removing the outside list brackets L0|[T] produces a syntax error.
Why is "|" not symmetric? Is there a way to do what I want using "|"?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
|
不是“对称”的,因为非空列表有头和尾,其中头是单个项目,尾部是另一个列表。在表达式[foo | bar]
foo
表示列表的头部,bar
表示列表的尾部。如果尾部不是正确的列表,则结果也不会是正确的列表。如果头是一个列表,则结果将只是一个以该列表作为其第一个元素的列表。没有办法在小于 O(n) 的时间内追加到链表的末尾。这就是为什么通常避免使用
++
的原因。如果有特殊的语法要附加在列表的末尾,它仍然需要花费 O(n) 时间,并且使用该语法并不会让你比使用++< 更成为一个“好编辑” /代码> 会的。
如果您想避免每次插入的 O(n) 成本,则需要预先添加然后反转。如果你愿意付出代价,你不妨使用
++
。有关列表如何工作的更多详细信息:
[ x | y ]
是一种称为 cons cell 的东西。用 C 语言来说,它基本上是一个有两个成员的结构体。真列表可以是空列表 ([]
),也可以是第二个成员是真列表的 cons 单元格(在这种情况下,第一个成员称为其头,第二个成员称为其尾部) )。因此,当您编写
[1, 2, 3]
时,会创建以下 cons 单元格:[1 | [2 | [3 | []]]]
。即列表被表示为一个 cons 单元,其第一个成员(其头)为 1,第二个成员(尾部)是另一个 cons 单元。另一个 cons 单元有 2 作为其头部,还有另一个 cons 单元作为其尾部。该单元格以 3 作为其头部,以空列表作为其尾部。遍历这样的列表是通过首先作用于列表的头部,然后调用列表的尾部的遍历函数来递归地完成的。
现在,如果您想在该列表中添加一个项目,这非常简单:您只需创建另一个 cons 单元,其头部是新项目,尾部是旧列表。
然而,附加项目的成本要高得多,因为创建单个 cons 单元是不够的。您必须创建一个与旧列表相同的列表,除了最后一个 cons 单元的尾部必须是一个新的 cons 单元,其头是新元素,尾部是空列表。因此,如果不遍历整个列表,就无法追加到列表,即 O(n)。
|
is not "symmetric" because a non-empty list has a head and a tail where the head is a single item and the tail is another list. In the expression[foo | bar]
foo
denotes the head of the list andbar
is the tail. If the tail is not a proper list, the result won't be a proper list either. If the head is a list, the result will simply be a list with that list as its first element.There is no way to append at the end of a linked list in less than O(n) time. This is why using
++
for that is generally shunned. If there were special syntax to append at the end of the list, it would still need to take O(n) time and using that syntax wouldn't make you any more of a "good erlanger" than using++
would.If you want to avoid the O(n) cost per insertion, you'll need to prepend and then reverse. If you're willing to pay the cost, you might just as well use
++
.A little more detail on how lists work:
[ x | y ]
is something called a cons cell. In C terms it's basically a struct with two members. A proper list is either the empty list ([]
) or a cons cell whose second member is a proper list (in which case the first member is called its head, and the second member is called its tail).So when you write
[1, 2, 3]
this creates the following cons cells:[1 | [2 | [3 | []]]]
. I.e. the list is represented as a cons cell whose first member (its head) is 1 and the second member (the tail) is another cons cell. That other cons cell has 2 as its head and yet another cons cell as its tail. That cell has 3 as its head and the empty list as its tail.Traversing such a list is done recursively by first acting on the head of the list and then calling the traversal function on the tail of the list.
Now if you want to prepend an item to that list, this is very easy: you simply create another cons cell whose head is the new item and whose tail is the old list.
Appending an item however is much more expensive because creating a single cons cell does not suffice. You have to create a list that is the same as the old one, except the tail of the last cons cell must be a new cons cell whose head is the new element and whose tail is the empty list. So you can't append to a list without going through the whole list, which is O(n).