程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长

+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

暂无数据

python有列表构造函数吗?

发布于2019-09-21 10:52     阅读(257)     评论(0)     点赞(26)     收藏(1)


python是否具有像consOCaml(::)(或lisp)中那样的列表构造函数,它接受head元素和tail列表,并返回新列表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

解决方案


要回答您的问题,没有与您通常在所谓的“功能”语言(lisp,OCaml,Haskell等)中发现的缺点直接等效的东西。

这是因为有两个相互竞争的模型来表示编程语言中的元素列表。

链表

您似乎熟悉的一个称为链表。

链表由cons单元组成,每个单元包含两个引用:

  • 第一个指向列表的元素,称为head
  • 另一个指向列表中的下一个cons单元,并且是尾部

因为列表很少是无限的,所以最后一个const单元通常会指向一个特殊值,即空列表,有时称为nil

如果要将列表保存在变量中以备将来参考,则应保留对第一个cons单元的引用。

这是Wikipedia的直观表示

在此模型中,必须通过创建一个新的cons单元格在前面添加元素来构造每个列表,指向该新元素作为其头部,并指向先前构造的子列表作为其尾部。这就是为什么cons运算符有时称为list构造函数的原因

数组

这是命令式语言(例如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个点!

如果您需要多次访问非常大的列表中的随机元素,那么数组会更好。

在中间插入一个元素

假设您现在想在中间插入一个元素。

带有链表:

  • 您可以找到与插入点之前的最后一个元素相对应的con单元格。
  • 您将创建一个新的cons单元格,其头部指向您要添加的元素,并且尾部与刚刚定位的cons单元格相同。
  • 您现在可以更改此单元格的尾部以指向新创建的单元格。

使用数组时,就像在中间添加元素一样,您将需要将每个元素复制到插入点的右边,在右边留一个空格!

在这种情况下,这就是明显更好的链表。



所属网站分类: 技术文章 > 问答

作者:黑洞官方问答小能手

链接:https://www.pythonheidong.com/blog/article/118019/af84061a156cf235db0c/

来源:python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

26 0
收藏该文
已收藏

评论内容:(最多支持255个字符)