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

그래서, 파이썬에서 위에서 설명한 것을 달성하는 방법이 있습니까? 변수는 목록이 아니어도되며 예제로 사용했습니다.

감사!

답변:


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 를 제안 하려고 했지만 사전 구축 된 솔루션이있을 수 있다고 생각했습니다.
senderle

파이썬이 솔루션을 어떻게 구현합니까? 새 요소가 추가되면 deque가 왼쪽 요소를 튀어 나오나요?
아오啸

파이썬에는 list ()를 사용하여 필요할 때 목록으로 바꿀 수있는 많은 목록 데이터 구조가 있습니다. 예를 들어 사전을 작성하고 목록 (MyDict)을 사용해보십시오.
Michael Dillon

1
@xiao는 양단 대기열이므로 양쪽 끝에 효율적으로 추가 할 수 있습니다. 실제로 deque의 앞에 추가 할 appendleft 메소드가 있습니다. maxlen이 있고 append / appendleft가 넘어 가면 한 항목이 다른 쪽 끝에서 제거됩니다.
lambacck

1
이 솔루션은 단순한 listac 배열 과 달리 이중 연결 목록이므로 큰 청크의 복사본에 대해 느립니다 .
Gulzar

14

이 같은 문제가 발생했습니다 ... deque의 maxlen = 5는 액세스 속도 / 신뢰성 문제로 인해 지원되는 옵션이 아닙니다.

간단한 솔루션 :

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

추가 한 후 'l'의 가장 최근 5 개 요소로 'l'을 재정의하십시오.

print(l)

Done이라고 부릅니다.

당신의 목적을 위해 당신은 바로 거기에서 멈출 수 있지만 ... 나는 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
또한 insert, extendsetitem메서드 ( l[1:1] = range(100)) 를 확장해야 오류가 발생하지 않습니다.
Lauritz V. Thaulow

1
고려하십시오 del self[0].
Alfe 2015-06-08

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

다시 기능으로 제어 할 수 있습니다. 커지면 처음에 버리십시오.
Senthil Kumaran

return에가 insert()있기 때문에, 무의미 list.insert의 위치에서 동작하기위한 것입니다.
glglgl

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