Python, wodurch eine Liste auf eine feste Größe gezwungen wird


80

In Python (3) möchte ich eine Liste erstellen, die die letzten 5 eingegebenen Variablen enthält. Hier ist ein Beispiel:

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

Gibt es in Python eine Möglichkeit, das zu erreichen, was oben gezeigt wurde? Die Variable muss keine Liste sein, ich habe sie nur als Beispiel verwendet.

Vielen Dank!

Antworten:


140

Möglicherweise möchten Sie stattdessen ein collection.deque- Objekt mit dem Konstruktorargument maxlen verwenden:

>>>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, nett - Ich wollte gerade eine Unterklassenliste als Gnibbler vorschlagen, aber ich vermutete, dass es eine vorgefertigte Lösung geben könnte.
senderle

Wie implementiert Python die Lösung? Wird das linke Element deque herausspringen, wenn ein neues Element hinzugefügt wird?
Xiao 10

Python verfügt über viele Listendatenstrukturen, die mithilfe von list () bei Bedarf in eine Liste umgewandelt werden können. Machen Sie zum Beispiel ein Diktat und probieren Sie die Liste (MyDict) aus.
Michael Dillon

1
@xiao es ist eine Warteschlange mit zwei Enden, was bedeutet, dass Sie effizient zu beiden Enden hinzufügen können. Tatsächlich gibt es eine Methode zum Anhängen an die Vorderseite der Deque. Wenn ein Maxlen vorhanden ist und das Anhängen / Anhängen übergeht, wird ein Element vom anderen Ende entfernt.
Lambacck

1
Bitte beachten Sie, dass diese Lösung für Kopien großer Blöcke langsam ist, da es sich um eine doppelt verknüpfte Liste handelt, im Gegensatz zu einem einfachen listAC-Array.
Gulzar

14

Sie könnten Unterklasse 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
Sie würden auch die Notwendigkeit zu verlängern insert, extendund setitemMethoden ( l[1:1] = range(100)) für diese narrensicher zu sein.
Lauritz V. Thaulow

1
Überlegen Sie del self[0].
Alfe

1
und vielleicht außer Kraft setzen müssen __add__auch
Lee

13

Ich bin auf dasselbe Problem gestoßen ... maxlen = 5 von deque war aufgrund von Problemen mit der Zugriffsgeschwindigkeit / Zuverlässigkeit KEINE unterstützte Option.

EINFACHE Lösung:

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

Nachdem Sie angehängt haben, definieren Sie 'l' einfach als die letzten fünf Elemente von 'l' neu.

print(l)

Nennen wir es fertig.

Für deine Zwecke könntest du genau dort anhalten ... aber ich brauchte ein Popleft (). Während pop () ein Element von rechts entfernt, wo es gerade angehängt wurde ... pop (0) entfernt es von links:

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

Hutspitze an James bei Tradewave.net

Keine Notwendigkeit für Klassenfunktionen oder Deque.

Weiter ... links anhängen und rechts einfügen:

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

Wäre Ihr appendleft () -Äquivalent, wenn Sie Ihre Liste ohne Verwendung von deque von vorne laden möchten

Schließlich, wenn Sie von links anhängen ...

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

dequeist für den wahlfreien Zugriff langsam und unterstützt kein Schneiden. Auf Gnibblers Vorschlag hin habe ich eine komplette listUnterklasse zusammengestellt.

Es ist jedoch so konzipiert, dass es nur von rechts nach links "rollt". Zum Beispiel hat insert()eine "vollständige" Liste keine Auswirkung.

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

Sie könnten eine begrenzte Sammlung in PyMongo verwenden - es ist übertrieben, aber es macht den Job gut:

import pymongo

#create collection
db.createCollection("my_capped_list",{capped:True, max:5})

#do inserts ...

#Read list
l = list(db.my_capped_list.find())

Daher rufen my_capped_listSie bei jedem Aufruf die letzten 5 eingefügten Elemente ab.


0

Wenn Sie eine solche Funktion benötigen, schreiben Sie meistens eine Funktion, die die Liste übernimmt und dann die letzten fünf Elemente zurückgibt.

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

Wenn Sie jedoch wirklich eine benutzerdefinierte Liste mit einer Obergrenze für fünf Elemente wünschen, können Sie die integrierte Liste und ihre Methoden überschreiben. Sie würden für alle Methoden so etwas tun.

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

Der Grund, warum ich keine Funktion verwenden kann, die einen Teil der Liste zurückgibt, ist, dass die Liste mit der Zeit SEHR groß wird und viele nutzlose Daten enthält, die nie wieder verwendet werden.
Lanrat

Das kann wieder von der Funktion gesteuert werden. Wenn das groß wird, vergießen Sie die am Anfang.
Senthil Kumaran

Das returnIn insert()ist sinnlos, weil list.insertes an Ort und Stelle arbeiten soll.
glglgl

-3

Dies kann so einfach sein wie die folgende Lösung

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))
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.