如何在erlang中连接列表而不创建嵌套列表? [英] How to concat lists in erlang without creating nested lists?

查看:82
本文介绍了如何在erlang中连接列表而不创建嵌套列表?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图成为一个好的erlanger并避免++。我需要在一个列表的末尾添加一个元组,而不需要创建一个嵌套的列表(而且希望不需要反向构建它)。给定元组T并列出L0和L1:



当我使用 [T | L0] 时,我得到 [tuple,list0] / strong>。



但是当我使用 [L0 | T] 时,我得到嵌套列表 [[list0] | tuple] 即可。同样, [L0 | L1] 返回 [[list0] | list1]



L0 | [T] 产生语法错误。



为什么是|不对称?有没有办法使用|进行操作?

解决方案

| 不是对称的,因为非空列表有头和尾,头是单个项,尾是另一个列表。在表达式 [foo | bar] foo 表示列表的头, bar 是尾部。如果尾巴不是正确的列表,结果也不会是正确的列表。如果头是一个列表,结果将只是一个列表,该列表作为它的第一个元素。



没有办法在链表的末尾附加小于O(n)时间。这就是为什么通常会使用 ++ 。如果在列表末尾附加了特殊的语法,它仍然需要花费O(n)个时间,并且使用该语法不会使您再次使用好的erlanger,而不是使用 ++ 会。



如果您想避免每次插入的O(n)费用,您需要先加后面然后反转。如果您愿意支付费用,您也可以使用 ++



再多一点关于列表如何工作的细节:



[x | y] 是一个叫做cons单元格的东西。在C语言中,它基本上是一个具有两个成员的结构。一个正确的列表是空列表( [] )或第二个成员是正确列表的cons单元(在这种情况下,第一个成员称为其头,第二个成员被称为尾部)



所以当你写 [1,2,3] 以下conscell: [1 | [2 | [3 | []]]] 。即列表被表示为其第一个成员(其头)为1并且第二个成员(尾部)是另一个cons单元的cons单元。那个其他的电池有2个作为它的头,而另一个cons电池作为它的尾巴。该单元格具有3个作为其头部,空列表作为其尾部。



遍历这样的列表是递归地完成的,首先作用在列表的头部,然后调用列表尾部的遍历功能。



现在,如果您要将一个项目添加到该列表中,这很容易:您只需创建另一个cons单元,其头是新项目,其尾部是旧列表。



然而,添加项目要花费更多,因为创建单个cons单元格是不够的。您必须创建与旧的列表相同的列表,除了最后一个cons单元格的尾部必须是新的cons单元格,其头是新元素,其尾部是空列表。所以你不能通过整个列表来附加到列表中,这是O(n)。


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 "|"?

解决方案

| 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 and bar 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).

这篇关于如何在erlang中连接列表而不创建嵌套列表?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆