Python、リストを固定サイズに強制


83

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では、上に示したものを達成する方法はありますか?変数はリストである必要はありません。例として使用しました。

ありがとう!

回答:


145

代わりに、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)を試してください。
マイケルディロン

1
@xiaoこれは両端キューであるため、どちらの端にも効率的に追加できます。実際、両端キューの前に追加するappendleftメソッドがあります。maxlenが存在し、append / appendleftがオーバーする場合、一方のアイテムがもう一方の端から削除されます。
lambacck 2011年

1
このソリューションは、listAC配列である単純なものとは対照的に、二重にリンクされたリストであるため、大きなチャンクのコピーでは遅いことに注意してください。
ガルザー

14

これと同じ問題が発生しました...アクセス速度/信頼性の問題のため、dequeのmaxlen = 5はサポートされていませんでした。

簡単な解決策:

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

追加した後、「l」を「l」の最新の5つの要素として再定義するだけです。

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

dequeを使用せずにリストをフロントロードする場合は、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

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]
アルフェ2015年

1
そして多分__add__またオーバーライドする必要がある
Lee

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

ほとんどの場合、このような機能が必要な場合は、リストを取得して最後の5つの要素を返す関数を記述します。

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

ただし、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

リストの一部を返す関数を使用できない理由は、リストが時間の経過とともに非常に大きくなり、二度と使用されない多くの役に立たないデータを保持するためです。
lanrat 2011年

これも関数で制御できます。大きくなった場合は、最初に流してください。
セントヒルクマラン

return中にはinsert()ので、無意味である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))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.