Python, buộc một danh sách có kích thước cố định


83

Trong Python (3), tôi muốn tạo một danh sách chứa 5 biến cuối cùng được nhập vào đó. Đây là một ví dụ:

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

Vì vậy, trong python, có cách nào để đạt được những gì được trình bày ở trên? Biến không cần phải là một danh sách, tôi chỉ sử dụng nó như một ví dụ.

Cảm ơn!

Câu trả lời:


145

Thay vào đó, bạn có thể muốn sử dụng một đối tượng collection.deque với đối số hàm tạo maxlen:

>>>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, thật tuyệt - Tôi đã định đề xuất danh sách phân lớp con ala gnibbler nhưng tôi nghi ngờ có thể có một giải pháp được tạo sẵn.
gửi

Làm thế nào python thực hiện giải pháp? Deque có bật ra phần tử bên trái khi phần tử mới được thêm vào không?
xiao 啸

Python có rất nhiều cấu trúc dữ liệu danh sách có thể được chuyển thành danh sách khi bạn cần bằng cách sử dụng list (). Ví dụ, tạo một danh sách chính tả và thử (MyDict).
Michael Dillon

1
@xiao nó là một hàng đợi kết thúc kép có nghĩa là bạn có thể thêm vào một trong hai đầu một cách hiệu quả. Trên thực tế có một phương pháp appendleft để nối vào phía trước của deque. Nếu một maxlen có mặt và append / appendleft sẽ đi qua một mục sẽ bị xóa khỏi đầu kia.
lambacck

1
Xin lưu ý rằng giải pháp này là chậm đối với các bản sao của các khối lớn, vì nó là một danh sách được liên kết kép, trái ngược với một đơn giản listlà mảng ac.
Gulzar

14

Tôi đã gặp phải vấn đề tương tự này ... maxlen = 5 từ deque KHÔNG phải là một tùy chọn được hỗ trợ do các vấn đề về tốc độ truy cập / độ tin cậy.

Giải pháp ĐƠN GIẢN:

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

Sau khi bạn thêm, chỉ cần xác định lại 'l' là năm phần tử gần đây nhất của 'l'.

print(l)

Gọi là Xong.

Vì mục đích của bạn, bạn có thể dừng lại ngay tại đó ... nhưng tôi cần một popleft (). Trong khi pop () xóa một mục từ bên phải nơi nó vừa được thêm vào ... pop (0) xóa nó từ bên trái:

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

Mẹo dành cho James tại Tradewave.net

Không cần hàm lớp hoặc deque.

Hơn nữa ... để nối bên trái và bên phải:

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

Tương đương appendleft () của bạn nếu bạn muốn tải trước danh sách của mình mà không sử dụng deque

Cuối cùng, nếu bạn chọn nối từ bên trái ...

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

Bạn có thể phân lớp 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
Bạn cũng cần phải mở rộng insert, extendsetitemcác phương thức ( l[1:1] = range(100)) để điều này được dễ dàng.
Lauritz V. Thaulow 22/10/12

1
Hãy cân nhắc del self[0].
Alfe

1
và có lẽ cần phải ghi đè __add__cũng
Lee

7

dequechậm đối với truy cập ngẫu nhiên và không hỗ trợ cắt. Theo gợi ý của gnibbler, tôi đã tập hợp một listlớp con hoàn chỉnh .

Tuy nhiên, nó được thiết kế để "cuộn" từ phải sang trái. Ví dụ, insert()trên danh sách "đầy đủ" sẽ không có hiệu lực.

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

Bạn có thể sử dụng một bộ sưu tập giới hạn trong PyMongo - nó quá mức cần thiết, nhưng nó hoạt động tốt:

import pymongo

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

#do inserts ...

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

Do đó bất kỳ lúc nào bạn gọi my_capped_list, bạn sẽ truy xuất 5 phần tử cuối cùng được chèn.


0

Thông thường khi bạn cần một loại tiện ích như vậy, bạn sẽ viết một hàm lấy danh sách và sau đó trả về năm phần tử cuối cùng.

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

Nhưng nếu bạn thực sự muốn có một danh sách tùy chỉnh, có giới hạn về năm yếu tố, bạn có thể ghi đè danh sách tích hợp sẵn và đó là các phương thức, bạn sẽ làm như thế này, đối với tất cả các phương thức của nó.

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

Lý do tại sao tôi không thể sử dụng một hàm trả về một phần của danh sách là bởi vì danh sách sẽ trở nên RẤT lớn theo thời gian và nó sẽ chứa rất nhiều dữ liệu vô dụng mà sẽ không bao giờ được sử dụng nữa.
lanrat

Điều đó một lần nữa có thể được kiểm soát bởi chức năng. nếu phát triển lớn, rụng những cái ở đầu.
Senthil Kumaran

Bên returntrong insert()là vô nghĩa, bởi vì list.insertnó được thiết kế để hoạt động tại chỗ.
glglgl 22/10/12

-3

Nó có thể đơn giản như giải pháp dưới đây

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))
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.