【问题标题】:Pop multiple items from the beginning and end of a list从列表的开头和结尾弹出多个项目
【发布时间】:2014-08-06 08:36:39
【问题描述】:

假设我有一个这样的项目列表:

mylist=['a','b','c','d','e','f','g','h','i']

我想从左侧弹出两个项目(即ab)和从右侧弹出两个项目(即h,i)。我想要最简洁干净的方式来做到这一点。我自己也可以这样做:

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

还有其他选择吗?

【问题讨论】:

  • 如果你有足够的内存,使用列表切片。
  • 您是否在此处使用collections.deque() object 而不是列表?因为 这与使用普通的 list 类型有很大的不同没有 list.popleft() 方法,在标准库中只有deque 对象具有该方法。
  • 会不会不能用.pop((len(yourArray)-1))之类的?

标签: python arrays list


【解决方案1】:

从性能的角度来看:

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

代码

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

【讨论】:

    【解决方案2】:

    您可以切出一个新列表,保持旧列表不变:

    mylist=['a','b','c','d','e','f','g','h','i']
    newlist = mylist[2:-2]
    

    newlist 现在返回:

    ['c', 'd', 'e', 'f', 'g']
    

    您也可以覆盖对旧列表的引用:

    mylist = mylist[2:-2]
    

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

    您自己尝试做的事情是对内存友好的,缺点是它会改变您的旧列表,但popleft 不适用于 Python 中的列表,它是 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:]
    

    【讨论】:

      【解决方案3】:

      如果您不想保留这些值,可以删除索引:

      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() object。如果是这样,*坚持使用popleft(),因为这比在列表对象上切片或del 高效得多。

      【讨论】:

      • 在内存使用方面与切片相比如何?
      • @wnnmaw:没有创建新的列表对象;所以在内存方面,这比切片更有效。但是,您需要一个大列表对象才能有所作为。
      • 为什么需要, myList[:2] 部分?这真的有什么作用吗?
      • @holroy:问题要求删除列表的第一个和最后两个元素。如果没有 myList[:2] 部分,您将不会删除前两个元素。
      • @MartijnPieters,是的,当然......忘记了问题的那一部分,因为我只想删除前两个元素!谢谢!
      【解决方案4】:

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

      所以myList[2:-2]

      【讨论】:

        【解决方案5】:

        对我来说,这是使用列表理解的最漂亮的方法:

        >> 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 项。
        • 你是对的。我修复了这个例子。我不知道为什么我以前没有注意到这一点。
        【解决方案6】:
        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']
        

        【讨论】:

        • 请添加更多详细信息,说明此代码如何解决所提出的问题。
        【解决方案7】:

        Python3 有一些很酷的东西,类似于 JS 中的 rest(但是如果你需要弹出很多东西会很痛苦)

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

        【讨论】:

          猜你喜欢
          • 2019-05-25
          • 2014-06-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-01-26
          • 1970-01-01
          • 2017-07-05
          相关资源
          最近更新 更多