【问题标题】:Taking list's tail in a Pythonic way?以 Pythonic 的方式获取列表的尾部?
【发布时间】:2011-04-23 15:21:30
【问题描述】:
from random import randrange
data = [(randrange(8), randrange(8)) for x in range(8)]

我们必须测试第一项是否等于一个尾巴。我很好奇,我们如何以最简单的方式做到这一点而不将尾部项目复制到新列表中?请考虑到这段代码在 update() 方法中执行了很多次,因此它必须尽可能快。

使用额外的列表(我猜是不必要的内存浪费):

head = data[0]
result = head in data[1:]

好的,这是另一种方式(太冗长):

i = 1
while i < len(data):
    result = head == data[i]
    if result:
        break
    i+=1

解决这个问题的最 Pythonic 方法是什么?谢谢。

【问题讨论】:

  • 简单地说 result = data[0] in data[1:] 有什么问题?如果执行in 查询,列表切片只是一个迭代器,而不是一个副本。
  • 哎呀。我不知道。任何文档都说明了这一点?
  • @Aram Dulyan,什么版本的 python?当我以您描述的方式切割足够大的列表(大约一千万个元素)时,我可以在系统监视器上看到我的内存跳跃。我也需要看一些文档才能相信这一点。
  • 遗憾的是,获取元组的切片也会导致内存跳跃(Python 2.6)。我会认为不可变序列的切片将通过包装支持序列来实现。
  • lst = [1, 1]; it = iter(lst[1:]); lst[1] = 2; it.next() 给出1,再次建议/确认切片运算符确实为迭代目的创建了原始列表的副本。

标签: python


【解决方案1】:

尼克 D 的答案更好

使用islice。它不会复制列表,而是将您的第二个(优雅但冗长的)解决方案嵌入到 C 模块中。

import itertools

head = data[0]
result = head in itertools.islice(data, 1, None)

演示:

>>> a = [1, 2, 3, 1]
>>> head = a[0]
>>> tail = itertools.islice(a, 1, None)
>>> head in tail
True

请注意,您只能遍历一次,但如果您只想检查头部是否在尾部并且您担心记忆,那么我认为这是最好的选择。

【讨论】:

  • 谢谢!回到之前的评论,“data[1:] 中的 data[0]”确实不会创建列表的新副本吗?
  • 酷,我没有意识到你可以在迭代器上使用in。不过应该是itertools.islice(data, 1, None)——否则它会在第0个元素之后StopIteration
  • @intuited,很好看。我在制作演示时犯了错误并编辑了错误的行。 @varnie,随时。我不知道。请参阅我对该评论的回复。我很怀疑,想看看文档。我从没听说过,但我有点新手。
  • @varnie。你应该接受尼克 D 的回答,这样我就可以删除这个。他有更好的解决方案。
  • @AaronMcSmooth:完成。但无论如何,我发现你的解决方案也很有用。
【解决方案2】:

替代方法,

# 1
result = data.count(data[0]) > 1


# 2
it = iter(data)
result = it.next() in it

【讨论】:

  • #2 的改进,基于in 的第一个“参数”必须在测试开始之前进行评估:it = iter(data); it.next() in it
猜你喜欢
  • 1970-01-01
  • 2010-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-06
  • 2016-02-11
  • 2017-04-17
相关资源
最近更新 更多