Câu trả lời này ban đầu được viết để trả lời cho một câu hỏi đã được đánh dấu là trùng lặp:
Xóa tọa độ khỏi danh sách trên python
Có hai vấn đề trong mã của bạn:
1) Khi sử dụng remove (), bạn cố xóa các số nguyên trong khi bạn cần xóa một tuple.
2) Vòng lặp for sẽ bỏ qua các mục trong danh sách của bạn.
Hãy xem những gì xảy ra khi chúng tôi thực thi mã của bạn:
>>> L1 = [(1,2), (5,6), (-1,-2), (1,-2)]
>>> for (a,b) in L1:
... if a < 0 or b < 0:
... L1.remove(a,b)
...
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
TypeError: remove() takes exactly one argument (2 given)
Vấn đề đầu tiên là bạn chuyển cả 'a' và 'b' để xóa (), nhưng remove () chỉ chấp nhận một đối số duy nhất. Vậy làm thế nào chúng ta có thể khiến remove () hoạt động đúng với danh sách của bạn? Chúng tôi cần tìm ra từng yếu tố trong danh sách của bạn. Trong trường hợp này, mỗi người là một tuple. Để thấy điều này, hãy truy cập một yếu tố của danh sách (lập chỉ mục bắt đầu từ 0):
>>> L1[1]
(5, 6)
>>> type(L1[1])
<type 'tuple'>
Aha! Mỗi phần tử của L1 thực sự là một tuple. Vì vậy, đó là những gì chúng ta cần phải vượt qua để loại bỏ (). Các bộ dữ liệu trong python rất dễ dàng, chúng chỉ đơn giản được tạo bằng cách đặt các giá trị trong ngoặc đơn. "A, b" không phải là một tuple, nhưng "(a, b)" là một tuple. Vì vậy, chúng tôi sửa đổi mã của bạn và chạy lại nó:
# The remove line now includes an extra "()" to make a tuple out of "a,b"
L1.remove((a,b))
Mã này chạy mà không có bất kỳ lỗi nào, nhưng hãy xem danh sách mà nó xuất ra:
L1 is now: [(1, 2), (5, 6), (1, -2)]
Tại sao (1, -2) vẫn còn trong danh sách của bạn? Hóa ra việc sửa đổi danh sách trong khi sử dụng một vòng lặp để lặp lại nó là một ý tưởng rất tồi mà không được chăm sóc đặc biệt. Lý do (1, -2) vẫn còn trong danh sách là vị trí của từng mục trong danh sách đã thay đổi giữa các lần lặp của vòng lặp for. Hãy xem điều gì xảy ra nếu chúng ta cung cấp mã trên một danh sách dài hơn:
L1 = [(1,2),(5,6),(-1,-2),(1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
### Outputs:
L1 is now: [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Như bạn có thể suy ra từ kết quả đó, mỗi khi câu lệnh điều kiện đánh giá là đúng và một mục danh sách bị loại bỏ, lần lặp tiếp theo của vòng lặp sẽ bỏ qua việc đánh giá mục tiếp theo trong danh sách vì các giá trị của nó hiện nằm ở các chỉ số khác nhau.
Giải pháp trực quan nhất là sao chép danh sách, sau đó lặp lại danh sách ban đầu và chỉ sửa đổi bản sao. Bạn có thể thử làm như vậy:
L2 = L1
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
print L2 is L1
del L1
L1 = L2; del L2
print ("L1 is now: ", L1)
Tuy nhiên, đầu ra sẽ giống hệt như trước:
'L1 is now: ', [(1, 2), (5, 6), (1, -2), (3, 4), (5, 7), (2, 1), (5, -1), (0, 6)]
Điều này là do khi chúng ta tạo L2, python không thực sự tạo ra một đối tượng mới. Thay vào đó, nó chỉ tham chiếu L2 đến cùng một đối tượng như L1. Chúng tôi có thể xác minh điều này với 'là' khác với chỉ "bằng" (==).
>>> L2=L1
>>> L1 is L2
True
Chúng ta có thể tạo một bản sao thực sự bằng cách sử dụng copy.copy (). Sau đó, mọi thứ hoạt động như mong đợi:
import copy
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
L2 = copy.copy(L1)
for (a,b) in L1:
if a < 0 or b < 0 :
L2.remove((a,b))
# Now, remove the original copy of L1 and replace with L2
del L1
L1 = L2; del L2
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Cuối cùng, có một giải pháp sạch hơn là phải tạo một bản sao hoàn toàn mới của L1. Hàm đảo ngược ():
L1 = [(1,2), (5,6),(-1,-2), (1,-2),(3,4),(5,7),(-4,4),(2,1),(-3,-3),(5,-1),(0,6)]
for (a,b) in reversed(L1):
if a < 0 or b < 0 :
L1.remove((a,b))
print ("L1 is now: ", L1)
>>> L1 is now: [(1, 2), (5, 6), (3, 4), (5, 7), (2, 1), (0, 6)]
Thật không may, tôi không thể mô tả đầy đủ cách thức hoạt động của Reverse (). Nó trả về một đối tượng 'listreverseiterator' khi một danh sách được truyền cho nó. Đối với các mục đích thực tế, bạn có thể nghĩ về nó như tạo ra một bản sao đảo ngược của đối số của nó. Đây là giải pháp tôi khuyên dùng.