Bây giờ tôi biết rằng không an toàn để sửa đổi danh sách trong một vòng lặp lặp. Tuy nhiên, giả sử tôi có một danh sách các chuỗi và tôi muốn tự tước chuỗi. Có thay thế các giá trị đột biến được tính là sửa đổi?
Bây giờ tôi biết rằng không an toàn để sửa đổi danh sách trong một vòng lặp lặp. Tuy nhiên, giả sử tôi có một danh sách các chuỗi và tôi muốn tự tước chuỗi. Có thay thế các giá trị đột biến được tính là sửa đổi?
Câu trả lời:
Đó được coi là hình thức nghèo nàn. Thay vào đó, hãy sử dụng tính năng hiểu danh sách, với phép gán lát nếu bạn cần giữ lại các tham chiếu hiện có vào danh sách.
a = [1, 3, 5]
b = a
a[:] = [x + 2 for x in a]
print(b)
print b
câu lệnh được thực thi, bạn có thể biết nếu a
đã được sửa đổi tại chỗ chứ không phải thay thế. Một khả năng khác có thể là print b is a
để xem liệu cả hai có còn đề cập đến cùng một đối tượng hay không.
Vì vòng lặp bên dưới chỉ sửa đổi các yếu tố đã thấy, nên nó sẽ được coi là chấp nhận được:
a = ['a',' b', 'c ', ' d ']
for i, s in enumerate(a):
a[i] = s.strip()
print(a) # -> ['a', 'b', 'c', 'd']
Khác với:
a[:] = [s.strip() for s in a]
trong đó nó không yêu cầu tạo ra một danh sách tạm thời và một sự phân công của nó để thay thế cho bản gốc, mặc dù nó đòi hỏi nhiều hoạt động lập chỉ mục hơn.
Thận trọng: Mặc dù bạn có thể sửa đổi các mục theo cách này, bạn không thể thay đổi số lượng mục trong list
mà không có nguy cơ gặp phải sự cố.
Đây là một ví dụ về những gì tôi muốn nói là xóa một mục nhập làm rối loạn việc lập chỉ mục từ thời điểm đó:
b = ['a', ' b', 'c ', ' d ']
for i, s in enumerate(b):
if s.strip() != b[i]: # leading or trailing whitespace?
del b[i]
print(b) # -> ['a', 'c '] # WRONG!
(Kết quả là sai vì nó không xóa tất cả các mục cần có.)
Cập nhật
Vì đây là một câu trả lời khá phổ biến, nên đây là cách xóa các mục "tại chỗ" một cách hiệu quả (mặc dù đó không phải là câu hỏi chính xác):
b = ['a',' b', 'c ', ' d ']
b[:] = [entry for entry in b if entry.strip() == entry]
print(b) # -> ['a'] # CORRECT
for i in a
? Điều này rất phản trực giác, dường như khác với các ngôn ngữ khác và đã dẫn đến lỗi trong mã của tôi mà tôi phải gỡ lỗi trong một thời gian dài. Python Tutorial thậm chí không đề cập đến nó. Mặc dù phải có một số lý do cho nó?
a[i]
và s
) cho cùng một đối tượng trong cùng một dòng khi bạn không phải? Tôi muốn làm nhiều hơn a[i] = a[i].strip()
.
a[i] = s.strip()
chỉ có một hoạt động lập chỉ mục.
enumerate(b)
thực hiện một thao tác lập chỉ mục trên mỗi lần lặp và bạn đang thực hiện một thao tác khác với a[i] =
. AFAIK không thể thực hiện vòng lặp này trong Python chỉ với 1 thao tác lập chỉ mục cho mỗi lần lặp lặp :(
Một biến thể cho vòng lặp nữa, có vẻ sạch hơn đối với tôi với biến thể liệt kê ():
for idx in range(len(list)):
list[idx]=... # set a new value
# some other code which doesn't let you use a list comprehension
range(len(list))
trong Python một mùi mã.
enumerate
là một trình tạo nên nó không tạo ra một list.of tuples, nó tạo ra chúng cùng một lúc khi nó lặp qua danh sách. Cách duy nhất để biết cái nào chậm hơn sẽ là timeit
.
Sửa đổi từng thành phần trong khi lặp lại một danh sách là tốt, miễn là bạn không thay đổi thêm / loại bỏ các yếu tố thành danh sách.
Bạn có thể sử dụng hiểu danh sách:
l = ['a', ' list', 'of ', ' string ']
l = [item.strip() for item in l]
hoặc chỉ thực hiện C-style
vòng lặp for:
for index, item in enumerate(l):
l[index] = item.strip()
Không, bạn sẽ không thay đổi "nội dung" của danh sách, nếu bạn có thể thay đổi chuỗi theo cách đó. Nhưng trong Python chúng không thể thay đổi. Bất kỳ hoạt động chuỗi trả về một chuỗi mới.
Nếu bạn có một danh sách các đối tượng bạn biết là có thể thay đổi, bạn có thể làm điều này miễn là bạn không thay đổi nội dung thực tế của danh sách.
Vì vậy, bạn sẽ cần phải làm một bản đồ của một số loại. Nếu bạn sử dụng biểu thức trình tạo, [thao tác] sẽ được thực hiện khi bạn lặp lại và bạn sẽ tiết kiệm bộ nhớ.
Câu trả lời được đưa ra bởi Jemshit Iskenderov và Ignacio Vazquez-Abrams là thực sự tốt. Nó có thể được minh họa thêm với ví dụ này: hãy tưởng tượng rằng
a) Một danh sách có hai vectơ được đưa cho bạn;
b) bạn muốn duyệt qua danh sách và đảo ngược thứ tự của từng mảng
Hãy nói rằng bạn có
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i = i[::-1] # this command does not reverse the string
print([v,b])
Bạn sẽ nhận được
[array([1, 2, 3, 4]), array([3, 4, 6])]
Mặt khác, nếu bạn làm
v = np.array([1, 2,3,4])
b = np.array([3,4,6])
for i in [v, b]:
i[:] = i[::-1] # this command reverses the string
print([v,b])
Kết quả là
[array([4, 3, 2, 1]), array([6, 4, 3])]
Vẫn chưa rõ câu hỏi của bạn về tiêu chí quyết định loại bỏ chuỗi nào, nhưng nếu bạn có hoặc có thể lập danh sách các chuỗi mà bạn muốn xóa, bạn có thể thực hiện như sau:
my_strings = ['a','b','c','d','e']
undesirable_strings = ['b','d']
for undesirable_string in undesirable_strings:
for i in range(my_strings.count(undesirable_string)):
my_strings.remove(undesirable_string)
thay đổi my_strings thành ['a', 'c', 'e']