2010-07-04 84 views
25

Tôi đang cố sửa đổi các mục trong danh sách bằng cách sử dụng vòng lặp for, nhưng tôi gặp lỗi (xem bên dưới). Mẫu mã:Sửa đổi các mục danh sách trong vòng lặp (python)

#!/usr/bin/env python 
# *-* coding: utf8 *-* 

data = [] 
data.append("some") 
data.append("example") 
data.append("data") 
data.append("here") 

for item in data: 
    data[item] = "everything" 

Lỗi:

Traceback (most recent call last): 
    File "./testy.py", line 11, in <module> 
    data[item] = "everything" 
TypeError: list indices must be integers, not str 

Có cách nào để giải quyết vấn đề này?

Trả lời

57

Hãy thử điều này thay vì:

for i in xrange(len(data)): 
    data[i] = "everything" 

Vấn đề cơ bản bạn đang gặp phải là khi bạn viết data[i], với data là một danh sách, i cần phải là một số nguyên, một chỉ số số vào danh sách. Nhưng trong vòng lặp

for item in data 

item là điều thực tế đó là trong danh sách, ví dụ: một chuỗi, không phải là chỉ số số trong những điều. xrange là một trình lặp mà tạo ra các số thay vì các giá trị trong danh sách, do đó bạn có thể sử dụng nó.

Một thay thế sẽ là

for i, _ in enumerate(data): 
    data[i] = "everything" 

Chức năng enumerate mang đến cho bạn một iterator qua các bộ dạng (index, item), vì vậy tất cả các bạn cần phải làm là lấy chỉ số và quên đi mục. Tôi không chắc chắn rằng cách này hay cách khác (enumerate hoặc xrange) sẽ nhanh hơn hoặc tốt hơn đáng kể vì tôi cho rằng danh sách lưu trữ độ dài của chúng trong biến để có thể truy cập nhanh chóng mà không cần đếm qua các yếu tố danh sách.

Tuy nhiên, nếu bạn cần các giá trị danh sách cũ để tính toán giá trị danh sách mới, cách enumerate có lẽ sẽ nhanh hơn một chút vì bạn tránh làm Python nhìn lên phần tử trong danh sách:

for i, item in enumerate(data): 
    data[i] = func(item) 

loại này điều được thể hiện tốt hơn như một sự hiểu biết danh sách, mặc dù:

data = [func(item) for item in data] 

Khi bạn làm điều này, Python sẽ đi qua mỗi mục trong data, áp dụng các chức năng để nó, và xây dựng một danh sách mới từ các kết quả tự động, vì vậy y Bạn không cần phải lo lắng về việc đưa kết quả của func(item) vào đúng vị trí trong danh sách. Ví dụ ban đầu của bạn thực sự có thể được thể hiện dưới dạng

data = ["everything" for item in data] 
+0

Có vẻ hơi lạ (hoặc workaround), nhưng nó hoạt động một cách chính xác. Tôi không biết rằng các mục ghi đè (trong danh sách) phải được cấp ID của họ. Cảm ơn. –

+4

@ sigo: đó thực sự không phải là một giải pháp nào cả, đó là cách chính xác 100% và hoàn toàn bình thường để thực hiện loại nhiệm vụ này (nhưng lưu ý những gì tôi đã nói về việc hiểu danh sách). –

+2

Trong trường hợp cụ thể này, việc hiểu danh sách có thể được thay thế bằng dữ liệu 'data = [" mọi thứ "nhanh hơn * len (dữ liệu)'. – EOL

5

Các mục danh sách được truy cập theo chỉ số nguyên, i. e. trong ví dụ của bạn data[1] == 'example'. Đây là lý do tại sao Python phàn nàn khi bạn đang sử dụng chuỗi như một tra cứu.

Nếu bạn muốn tìm một phần tử trong một danh sách bằng giá trị của nó, bạn có thể sử dụng data.index("value"):

data[data.index("some")] = "something else" 

Nhưng nếu bạn chỉ muốn để lặp qua chúng, sử dụng enumerate() như David đề nghị.

0

việc lập chỉ mục danh sách bằng số nguyên có thể không hiệu quả. Có khả năng là python lưu trữ các phần tử danh sách bằng cách sử dụng bảng được nối kết với các con trỏ nằm bên dưới.Trong trường hợp này, để tìm một mục cụ thể, python phải duyệt qua danh sách cho đến khi mục thứ i.

Nó được gợi ý rằng việc sử dụng các định dạng như thế này có thể là hiệu quả: một [:] = [x * x cho x trong a]

Các vấn đề liên quan