从列表的开头和结尾弹出多个项目

51
假设我有一个像这样的项目列表:
mylist=['a','b','c','d','e','f','g','h','i']

我想从左侧弹出两个项目(即ab),并从右侧弹出两个项目(即hi)。 我希望找到最简洁且清晰的方法。 我可以按以下方式自己完成:

for x in range(2):
    mylist.pop()
    mylist.pop(0)

还有其他的选择吗?


如果你有足够的RAM,使用列表切片。 - Paulo Scardine
4
你是否在这里使用了collections.deque()对象而不是列表?因为这会与使用普通的list类型有很大的不同!标准库中没有list.popleft()方法,仅deque对象具有该方法。 - Martijn Pieters
不可能使用.pop((len(yourArray)-1))等吗? - Harvey
7个回答

58

从性能角度来看:

  • mylist = mylist[2:-2]del mylist[:2];del mylist[-2:] 是等价的。
  • 它们比第一种解决方案 for _ in range(2): mylist.pop(0); mylist.pop() 快约3倍。

代码

iterations = 1000000
print timeit.timeit('''mylist=range(9)\nfor _ in range(2): mylist.pop(0); mylist.pop()''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\nmylist = mylist[2:-2]''', number=iterations)/iterations
print timeit.timeit('''mylist=range(9)\ndel mylist[:2];del mylist[-2:]''', number=iterations)/iterations

输出

1.07710313797e-06

3.44465017319e-07

3.49956989288e-07


16
你可以切割出一个新的列表,保持原有列表不变:
mylist=['a','b','c','d','e','f','g','h','i']
newlist = mylist[2:-2]

newlist现在返回:

['c', 'd', 'e', 'f', 'g']
您也可以覆盖对旧列表的引用:
mylist = mylist[2:-2]

上述两种方法都比下面的方法使用更多的内存。

你自己尝试的方式对内存友好,但缺点是会改变原列表,但在Python中,popleft 不适用于列表,而是 collections.deque 对象的方法。

在Python 3中,这个方法很有效:

for x in range(2):
    mylist.pop(0)
    mylist.pop()

在Python 2中,仅使用xrange和pop:

for _ in xrange(2):
    mylist.pop(0)
    mylist.pop()

按照Martijn的建议,最快的删除方法是这样的(这仅会删除列表对项的引用,而不一定是项本身):

del mylist[:2]
del mylist[-2:]

9
如果您不想保留这些值,可以删除这些索引:
del myList[-2:], myList[:2]

这仍然需要将所有剩余的项移动到列表中的位置。两个.popleft()调用也需要这样做,但至少现在列表对象可以在一步中处理这些移动。

不会创建新的列表对象。

演示:

>>> myList = ['a','b','c','d','e','f','g','h','i']
>>> del myList[-2:], myList[:2]
>>> myList
['c', 'd', 'e', 'f', 'g']

然而,从你使用 popleft 的方式来看,我强烈怀疑你正在使用一个 collections.dequeue() 对象。如果是这样的话,请继续使用 popleft(),因为这比在列表对象上切片或使用 del 更有效率。

1
相比于切片,这个在内存使用方面如何比较? - wnnmaw
1
@wnnmaw:不会创建新的列表对象;因此,从内存角度来看,这比切片更有效。但是,您需要一个大的列表对象才能产生差异。 - Martijn Pieters
你为什么需要 , myList[:2] 这部分?它真的有作用吗? - holroy
@holroy:该问题要求删除列表的前两个和后两个元素。如果没有 myList[:2] 部分,您将无法删除前两个元素。 - Martijn Pieters
@MartijnPieters,是的,当然...我忘记了问题的这一部分,因为我只想删除前两个元素!谢谢! - holroy

4
对我而言,使用列表推导式是最美观的方式来完成这个任务:
>> mylist=['a','b','c','d','e','f','g','h','i']
>> newlist1 = [mylist.pop(0) for idx in range(2)]
>> newlist2 = [mylist.pop() for idx in range(2)]

这将从列表的开头提取前两个元素,并从列表的末尾提取最后两个元素。其余项目保留在列表中。


如果你需要第一个或最后两个,你需要使用range(2)而不是range(1)。Range(1)只会弹出一个,range(n)将弹出n个项目。 - FranciscoRodríguezCuenca
1
你说得对。我修复了这个例子。我不确定为什么之前没有注意到。 - Chris Hubley

3

首先2个元素:myList[:2]
最后2个元素:mylist[-2:]

因此,myList[2:-2]


0
mylist = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o']

new_list = [mylist.pop(0) for _ in range(6) if len(mylist) > 0]

>>> new_list
['a', 'b', 'c', 'd', 'e', 'f']

new_list = [mylist.pop(0) for _ in range(6) if len(mylist) > 0]
>>> new_list
['g', 'h', 'i', 'j', 'k', 'l']

new_list = [mylist.pop(0) for _ in range(6) if len(mylist) > 0]
>>> new_list
['m', 'n', 'o']

1
请添加更多细节,解释这段代码如何解决所提出的问题。 - Skully

-2

Python3 有一个很酷的功能,类似于JS中的rest(但如果你需要频繁弹出很多东西,它会很麻烦)

mylist=['a','b','c','d','e','f','g','h','i']
_, _, *mylist, _, _ = mylist
mylist == ['c', 'd', 'e', 'f', 'g']  # true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接