Python,将列表强制为固定大小


80

在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中,有什么方法可以实现上面演示的内容吗?该变量不必是列表,我只是以它为例。

谢谢!

Answers:


140

您可能要使用具有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,但是我怀疑可能有一个预先构建的解决方案。
senderle'5

python如何实现解决方案?添加新元素时,双端队列是否弹出左侧元素?
萧啸

Python有很多列表数据结构,可以在需要时使用list()将其转换为列表。例如,做一个字典并尝试list(MyDict)。
迈克尔·狄龙

1
@xiao是一个双头队列,这意味着您可以有效地添加到任一端。实际上,有一个appendleft方法可附加到双端队列的前面。如果存在maxlen,并且append / appendleft将超过,则将一项从另一端删除。
兰巴克2011年

1
请注意,此解决方案对于大块副本来说速度较慢,因为它是一个双向链接列表,而不是简单list的ac数组。
Gulzar

14

你可以继承 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']
>>> 

2
你想也需要扩展insertextendsetitem方法(l[1:1] = range(100)),这是万无一失的。
Lauritz V. Thaulow 2012年

1
考虑一下del self[0]
Alfe 2015年

1
也许需要重写__add__

13

我遇到了同样的问题...由于访问速度/可靠性问题,不支持来自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

7

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()

1

您可以在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个元素。


0

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

>>> 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

我之所以不能使用返回部分列表的函数,是因为随着时间的推移,该列表将变得非常大,并且将容纳许多无用的数据,这些数据将不再使用。
兰拉特2011年

可以再次由该功能控制。如果长大了,一开始就掉掉。
Senthil Kumaran

returninsert()是没有意义的,因为list.insert打算就地操作。
glglgl 2012年

-3

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

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))
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.