python是否有一个像cons in OCaml (::) (或lisp)那样的列表构造函数,它接受head元素和tail列表,并返回一个新的list head::tail
我搜索了python构造函数,最后找到了关于__init__的其他内容。参见例如用Python创建一个列表-一些鬼鬼祟祟的事情发生了?
为了澄清,我要找的是下面在Python 在这个问题中找到的中的列表分解的逆序。
head, *tail = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]这意味着:
>>>head
1
>>> tail
[1, 2, 3, 5, 8, 13, 21, 34, 55]我正在寻找一个列表构造函数,例如cons或::
head :: tail => original list发布于 2016-02-10 17:46:27
为了回答你的问题,你通常在所谓的“函数式”语言(lisp、OCaml、Haskell等)中找不到与之直接对应的缺点。
这是因为有两个相互竞争的模型来表示编程语言中的元素列表。
链接列表
你似乎熟悉的是一个链接列表。
链接列表由cons单元格组成,每个单元格包含两个引用:
由于列表很少是无限的,最后一个const单元格通常指向一个特殊的值,即空列表,有时称为“零”。
如果要将列表保存在变量中以供以后引用,则应保留对第一个缺点单元格的引用。
在这个模型中,每个列表都必须通过在前面添加元素,创建一个新的反单元格,将新元素作为其头部,并指向先前构造的子列表作为其尾部。这就是为什么cons运算符有时被称为列表构造函数的原因。
列阵
这是命令式语言(如Python )通常首选的模型。在此模型中,列表只是对内存中某个范围的引用。
让我们假设您创建了一个列表,如下所示:
l = [1, 2, 3]每当您创建一个列表时,Python都会为它分配一小部分内存,以便存储元素,并为以后添加元素提供一些额外的空间。要存储它,只需存储对第一个元素和内存范围大小的引用,如下所示:
l <-- your variable
| ___ ___ ___ ___ ___ ___ ___ ___ ___
|-> | | | | | | | | | |
| 1 | 2 | 3 | | | | | | |
|___|___|___|___|___|___|___|___|___|如果决定在列表末尾添加元素,则可以使用append
l.append(4)其结果如下:
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|现在,假设您忘记了一个初始值0,现在您希望将它添加到前面。您可以很好地使用insert方法(插入位置为0):
l.insert(0, 0)但名单的开头没有空位!Python别无选择,只能把每个元素都取下来,然后一次在右边的地方复制它们:
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 1 | 2 | 3 | 4 | | | | | |
|___|___|___|___|___|___|___|___|___|
| | |__ |___
| |___ | | First, Python has to copy the four elements
|___ | | | one space to the right
___ _\/ _\/ \/_ _\/ ___ ___ ___ ___
| | | | | | | | | |
| | 1 | 2 | 3 | 4 | | | | |
|___|___|___|___|___|___|___|___|___|
Only then can it insert the 0 at the beginning
___ ___ ___ ___ ___ ___ ___ ___ ___
| | | | | | | | | |
| 0 | 1 | 2 | 3 | | | | | |
|___|___|___|___|___|___|___|___|___|对于这样一个小数组来说,这看起来不太像,但是想象一下您的数组要大得多,并且多次重复这个操作:您将花费那么多的时间来构建您的列表!
这就是为什么您不会在语言中找到一个列表构造函数,它使用数组来表示它们的列表,比如Python。
深潜:为什么两种不同的模式?
您现在可能想知道为什么不同的语言会选择不同的列表模型,以及这两种模型中的一种是否更优越。
这是因为这两种数据结构在不同的上下文中具有不同的性能。两个例子:
访问中间的元素
让我们假设您想要获得列表的第五个元素。
在链接列表中,您需要获得:
因此,您必须经过5次引用!
对于数组,这要简单得多:您知道第一个元素的引用。您只需要访问右边的引用4个点,因为元素都在一个连续的内存范围内!
如果您需要多次访问一个非常大的列表中的随机元素,那么数组就更好了。
在中间插入一个元素
假设您现在想在中间插入一个元素。
有一个链接的清单:
对于数组,就像在中间添加一个元素时一样,您需要将每个元素复制到插入点右侧一个空格的右边!
在这种情况下,这就是明显优越的链接列表。
发布于 2016-02-10 04:14:57
有些人建议你这样做:
a = 1
b = [2, 3, 4, 5]
c = [a] + b只要b是list类型,它就能工作。但是,通常您会发现自己正在处理一个对象,这个对象要么是列表,要么是元组,或者(在这里插入您最喜欢的可迭代对象)。在这种情况下,您可能更值得这样做:
a = 1
b = (2, 3, 4, 5)
c = [a]
c.extend(b)这使得整个事情都与b的类型无关(这允许您的代码更“鸭子”,这可能有点好)。。。
当然,还有其他选择。。。例如,您可以选择使用itertools
import itertools
a = 1
b = [2, 3, 4, 5]
lazy_c = itertools.chain([a], b)同样,我们不关心什么类型的可迭代b是有益的,并且我们获得了懒惰迭代的一个副作用--我们不会创建一个新的列表或元组。我们只需创建一个对象,在迭代时生成相同的内容。这可以节省内存(有时还会为您的CPU节省周期),但如果b也是一种类似生成器的对象,同时在其他地方进行迭代(这并不是偶然发生的),也会产生意想不到的后果。
发布于 2016-02-10 04:11:09
Python列表是可变的,而OCaml的列表具有不可变的值语义,但如果a是项,而b是列表,则可以使用[a] + b返回一个包含a的新列表,其中包含b中的项,而不修改a或b。不过,构建列表的一个更常见的模式是就地使用append或extend。
https://stackoverflow.com/questions/35306576
复制相似问题