99 votes

Comment forcer une liste à une taille fixe ?

En Python 3, je veux créer une liste qui contiendra les 5 dernières variables saisies.

En voici un exemple :

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

Alors, en python, existe-t-il un moyen de réaliser ce qui est démontré ci-dessus ? La variable n'a pas besoin d'être une liste, je l'ai juste utilisée comme exemple.

173voto

lambacck Points 4955

Vous pouvez utiliser un collections.deque avec l'argument maxlen du constructeur à la place :

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

0 votes

+1, bien -- j'étais sur le point de suggérer de sous-classer la liste à l'instar de grignoteuse mais je me doutais qu'il existait une solution préétablie.

0 votes

Comment python met-il en œuvre la solution ? Est-ce que le système deque fait sortir l'élément gauche lorsqu'un nouvel élément est ajouté ?

0 votes

Python possède de nombreuses structures de données de type liste qui peuvent être transformées en liste lorsque vous en avez besoin en utilisant list(). Par exemple, créez un dict et essayez list(MyDict).

17voto

user3680588 Points 72

J'ai rencontré le même problème... maxlen=5 de deque n'était PAS une option supportée à cause des problèmes de vitesse d'accès et de fiabilité.

Une solution simple :

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

Après l'ajout, il suffit de redéfinir "l" comme les cinq éléments les plus récents de "l".

print(l)

C'est fait.

Pour vos besoins, vous pourriez vous arrêter là... mais j'avais besoin d'un popleft(). Alors que pop() enlève un élément de la droite où il vient d'être ajouté... pop(0) l'enlève de la gauche :

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

Coup de chapeau à James de Tradewave.net

Il n'est pas nécessaire d'utiliser des fonctions de classe ou deque.

Plus loin... pour ajouter la gauche et la droite :

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

Ce serait l'équivalent de appendleft() si vous vouliez charger votre liste à l'avance sans utiliser deque

Enfin, si vous choisissez d'ajouter à partir de la gauche...

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

15voto

gnibbler Points 103484

Vous pouvez sous-classer 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']
>>>

3 votes

Vous devez également étendre le champ d'application de la insert , extend y setitem méthodes ( l[1:1] = range(100) ) pour que cela soit infaillible.

1 votes

Considérer del self[0] .

2 votes

Et qu'il est peut-être nécessaire de remplacer __add__ également

9voto

Julio Points 11

deque est lent pour l'accès aléatoire et ne permet pas le découpage en tranches. Suite à la suggestion de gnibbler, j'ai mis en place un système complet de list sous-classe.

Cependant, il est conçu pour "rouler" de droite à gauche uniquement. Par exemple, il est conçu pour rouler de droite à gauche, insert() sur une liste "complète" n'aura aucun effet.

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

0voto

Senthil Kumaran Points 14934

Le plus souvent, lorsque vous avez besoin d'une telle facilité, vous écrivez une fonction qui prend la liste et renvoie les cinq derniers éléments.

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

Mais si vous voulez vraiment une liste personnalisée, avec un plafond de cinq éléments, vous pouvez surcharger la liste intégrée et ses méthodes, vous feriez quelque chose comme ceci, pour toutes ses méthodes.

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

0 votes

La raison pour laquelle je ne peux pas utiliser une fonction qui renvoie une partie de la liste est qu'avec le temps, la liste deviendra TRÈS grande et contiendra de nombreuses données inutiles qui ne seront plus jamais utilisées.

0 votes

Cela peut également être contrôlé par la fonction. Si le nombre de personnes augmente, il faut se débarrasser de celles qui se trouvent au début.

0 votes

En return en insert() est inutile, car list.insert est destiné à fonctionner en place.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X