【问题标题】:How to force a list to a fixed size?如何强制列表为固定大小?
【发布时间】:2011-08-22 03:06:59
【问题描述】:

在 Python 3 中,我想创建一个列表,其中包含最后输入的 5 个变量。

这是一个例子:

>>>l = []
>>>l.append('apple')
>>>l.append('orange')
>>>l.append('grape')
>>>l.append('banana')
>>>l.append('mango')
>>>print(l)
['apple','orange','grape','banana','mango']
>>>l.append('kiwi')
>>>print(l)
['orange','grape','banana','mango','kiwi'] #only 5 items in list

那么,在 python 中,有没有办法实现上面演示的内容?变量不需要是列表,我只是用它作为例子。

【问题讨论】:

    标签: python list


    【解决方案1】:

    您可能希望使用带有 maxlen 构造函数参数的 collections.deque 对象:

    >>>l = collections.deque(maxlen=5)
    >>>l.append('apple')
    >>>l.append('orange')
    >>>l.append('grape')
    >>>l.append('banana')
    >>>l.append('mango')
    >>>print(l)
    deque(['apple','orange','grape','banana','mango'], maxlen=5)
    >>>l.append('kiwi')
    >>>print(l)
    deque(['orange','grape','banana','mango','kiwi'], maxlen=5) #only 5 items in list
    

    【讨论】:

    • +1,很好——我正要建议子类列表ala gnibbler,但我怀疑可能有一个预先构建的解决方案。
    • python如何实现解决方案?添加新元素时,deque会弹出左元素吗?
    • Python 有很多列表数据结构,可以在需要时使用 list() 将它们转换为列表。例如制作一个 dict 并试用 list(MyDict)。
    • @xiao 这是一个双端队列,这意味着您可以有效地添加到任一端。实际上有一个 appendleft 方法可以追加到双端队列的前面。如果存在 maxlen 并且 append/appendleft 将遍历一个项目,则从另一端删除。
    • 请注意这个解决方案对于大块的副本来说很慢,因为它是一个双向链表,而不是一个简单的list,它是一个 c 数组。
    【解决方案2】:

    我遇到了同样的问题...由于访问速度/可靠性问题,来自 deque 的 maxlen=5 不是受支持的选项。

    简单的解决方案:

    l = []
    l.append(x)                         # add 'x' to right side of list
    l = l[-5:]                          # maxlen=5
    

    追加后,只需将“l”重新定义为“l”的最新五个元素。

    print(l)
    

    完成。

    出于您的目的,您可以在此处停下来……但我需要一个 popleft()。而 pop() 从右侧删除刚刚附加的项目... pop(0) 从左侧删除它:

    if len(l) == 5:                     # if the length of list 'l' has reached 5 
        right_in_left_out = l.pop(0)    # l.popleft()
    else:                               #
        right_in_left_out = None        # return 'None' if not fully populated
    

    在 Tradewave.net 向 James 致敬

    不需要类函数或双端队列。

    进一步...向左追加并向右弹出:

    l = []
    l.insert(0, x)                      # l.appendleft(x)
    l = l[-5:]                          # maxlen=5
    

    如果您想在不使用双端队列的情况下预先加载您的列表,这将是您的 appendleft() 等价物

    最后,如果你选择从左边追加...

    if len(l) == 5:                     # if the length of list 'l' has reached 5 
        left_in_right_out = l.pop()     # pop() from right side
    else:                               #
        left_in_right_out = None        # return 'None' if not fully populated
    

    【讨论】:

      【解决方案3】:

      你可以继承list

      >>> class L(list):
      ...     def append(self, item):
      ...         list.append(self, item)
      ...         if len(self) > 5: del self[0]
      ... 
      >>> l = L()
      >>> l.append('apple')
      >>> l.append('orange')
      >>> l.append('grape')
      >>> l.append('banana')
      >>> l.append('mango')
      >>> print(l)
      ['apple', 'orange', 'grape', 'banana', 'mango']
      >>> l.append('kiwi')
      >>> print(l)
      ['orange', 'grape', 'banana', 'mango', 'kiwi']
      >>> 
      

      【讨论】:

      • 您还需要扩展 insertextendsetitem 方法 (l[1:1] = range(100)) 以确保万无一失。
      • 考虑del self[0]
      • 也许还需要覆盖__add__
      【解决方案4】:

      deque 随机访问速度慢,不支持切片。根据 gnibbler 的建议,我整理了一个完整的 list 子类。

      但是,它仅设计为从右向左“滚动”。例如,“完整”列表中的insert() 将无效。

      class LimitedList(list):
      
          # Read-only
          @property
          def maxLen(self):
              return self._maxLen
      
          def __init__(self, *args, **kwargs):
              self._maxLen = kwargs.pop("maxLen")
              list.__init__(self, *args, **kwargs)
      
          def _truncate(self):
              """Called by various methods to reinforce the maximum length."""
              dif = len(self)-self._maxLen
              if dif > 0:
                  self[:dif]=[]
      
          def append(self, x):
              list.append(self, x)
              self._truncate()
      
          def insert(self, *args):
              list.insert(self, *args)
              self._truncate()
      
          def extend(self, x):
              list.extend(self, x)
              self._truncate()
      
          def __setitem__(self, *args):
              list.__setitem__(self, *args)
              self._truncate()
      
          def __setslice__(self, *args):
              list.__setslice__(self, *args)
              self._truncate()
      

      【讨论】:

        【解决方案5】:

        你可以在 PyMongo 中使用一个有上限的集合——这有点矫枉过正,但它可以很好地完成工作:

        import pymongo
        
        #create collection
        db.createCollection("my_capped_list",{capped:True, max:5})
        
        #do inserts ...
        
        #Read list
        l = list(db.my_capped_list.find())
        

        因此,无论何时您调用 my_capped_list,您都会检索最后插入的 5 个元素。

        【讨论】:

          【解决方案6】:

          通常当您需要这种工具时,您会编写一个函数来获取列表,然后返回最后五个元素。

          >>> l = range(10)
          >>> l[-5:]
          

          但是如果你真的想要一个自定义列表,限制五个元素,你可以覆盖内置列表和它的方法,你会做这样的事情,所有它的方法。

          class fivelist(list):
              def __init__(self, items):
                  list.__init__(self, items[-5:])
          
              def insert(self, i, x):
                  list.insert(self, i, x)
                  return self[-5:]
          
              def __getitem__(self, i):
                  if i > 4:
                     raise IndexError
                  return list.__getitem__(self, i)
          
              def __setitem__(self, i, x):
                  if 0<= i <= 4:
                    return list.__setitem__(self, i, x)
                  else:
                    raise IndexError
          

          【讨论】:

          • 我不能使用返回部分列表的函数的原因是,随着时间的推移,列表会变得非常大,并且会保存许多永远不会再使用的无用数据.
          • 那又可以通过函数来​​控制了。如果变大,一开始就去掉。
          • insert() 中的return 毫无意义,因为list.insert 旨在就地操作。
          【解决方案7】:

          它可以像下面的解决方案一样简单

          lst = []
          arr_size = int(input("Enter the array size "))
          while len(lst) != arr_size:
              arr_elem= int(input("Enter the array element "))
              lst.append(arr_elem)
          
          sum_of_elements = sum(lst)
          
          print("Sum is {0}".format(sum_of_elements))
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-08-16
            • 1970-01-01
            • 1970-01-01
            • 2011-04-07
            • 1970-01-01
            • 2012-05-06
            • 2016-09-01
            • 1970-01-01
            相关资源
            最近更新 更多