2011-12-19 27 views
7

Cách tốt nhất để cập nhật giá trị trong danh sách bộ dữ liệu là gì?Python - Cập nhật giá trị trong danh sách các bộ dữ liệu

Tôi hiện đang làm như trong mã bên dưới, nhưng tôi cho rằng có một cách gọn gàng hơn và súc tích hơn.

>>> foo = [('a', 'hello'), ('b', 'world')] 
>>> bar = dict(foo) 
>>> bar['b'] = 'friend' 
>>> foo = bar.items() 
>>> foo 
[('a', 'hello'), ('b', 'friend')] 

Chỉnh sửa: Lý do sử dụng danh sách bộ không rõ ràng trong bài đăng gốc. Mục tiêu là cập nhật một số giá trị tiêu đề của một ứng dụng wsgi trong quá trình xử lý lỗi, đó là danh sách các bộ dữ liệu.

Xin cảm ơn trước.

+4

Tại sao bạn cần danh sách các hàng, không dict? Nếu thứ tự quan trọng, có [OrderedDict] (http://docs.python.org/library/collections.html#collections.OrderedDict) cho bạn. – DrTyrsa

+0

@DrTyrsa Điều này là để cập nhật các tiêu đề của một ứng dụng wsgi trong quá trình xử lý lỗi, đó là danh sách các bộ dữ liệu – Eric

Trả lời

6

Cấu trúc dữ liệu của bạn (danh sách bộ tuple) được gọi là danh sách liên kết tốt nhất. Như đã chỉ ra, có lẽ tốt hơn nên sử dụng từ điển vì bạn sẽ có được chi phí khấu hao tốt hơn cho hoạt động (chèn, xóa và tra cứu là O (1) cho từ điển, nhưng xóa và tra cứu là O (n) cho kết hợp danh sách).

Liên quan đến việc cập nhật danh sách liên kết của bạn bằng cách chuyển đổi danh sách thành từ điển và sau đó quay lại danh sách liên kết, phương pháp này có ba hạn chế. Nó là khá tốn kém, nó có thể thay đổi thứ tự của các mặt hàng, và nó sẽ loại bỏ trùng lặp.

Nếu bạn muốn tiếp tục sử dụng danh sách liên kết, có lẽ tốt hơn là chỉ cần sử dụng danh sách hiểu để cập nhật cấu trúc dữ liệu.Chi phí sẽ là O (n) trong thời gian và bộ nhớ, nhưng đó là những gì bạn có khi sử dụng một từ điển trung gian.

Đây là một cách đơn giản để làm điều đó (yêu cầu Python 2.5 bởi vì nó sử dụng các nhà điều hành ternary):

def update_in_alist(alist, key, value): 
    return [(k,v) if (k != key) else (key, value) for (k, v) in alist] 

def update_in_alist_inplace(alist, key, value): 
    alist[:] = update_in_alist(alist, key, value) 

>>> update_in_alist([('a', 'hello'), ('b', 'world')], 'b', 'friend') 
[('a', 'hello'), ('b', 'friend')] 
+0

Mã sạch và hiệu quả, Cảm ơn! – Eric

6

Vì bộ dữ liệu không thay đổi được, bạn sẽ cần thay thế bộ tuple bằng một bộ mới.

>>> foo[1] = (foo[1][0], "friend") 
>>> foo 
[('a', 'hello'), ('b', 'friend')] 

Tất nhiên, điều này chỉ hoạt động nếu bạn biết chỉ mục của mặt hàng bạn muốn thay thế. Nếu tất cả những gì bạn có là giá trị của mục đầu tiên, thì việc tìm kiếm trong danh sách cho chỉ mục đó không hiệu quả đặc biệt đối với các danh sách lớn hơn. Cũng vậy với ví dụ của bạn ở trên - chuyển đổi một danh sách thành một dict và ngược lại chỉ để thay đổi một vài mục không phải là giải pháp có thể mở rộng.

Như eumiro và DrTysra đã đề cập trong phần nhận xét, nếu cấu trúc dữ liệu của bạn cho phép, bạn có thể nên sử dụng lệnh dict (hoặc OrderedDict nếu thứ tự quan trọng).

+0

Tôi không nghĩ rằng chỉ mục được biết, chỉ mục đầu tiên trong bộ dữ liệu. – DrTyrsa

+0

@DrTyrsa là điểm tốt. –

2

Nó không hoàn toàn rõ ràng đối với tôi những gì bạn muốn đạt được. Không thể sửa đổi các bộ dữ liệu, vì vậy bạn không thể thay đổi ('b', 'world') thành một thứ khác. Nhưng bạn có thể sửa đổi danh sách khóa học:

foo[1] = ('b','friend') 

Cho dù điều đó có ý nghĩa hay không tùy thuộc vào trường hợp sử dụng của bạn. Nếu bạn cung cấp cho chúng tôi thêm chi tiết về mục đích thực sự của mã, chúng tôi có thể đề xuất các giải pháp tốt hơn.

+0

Cảm ơn câu trả lời của bạn, tôi đã cập nhật câu hỏi. Tôi muốn cập nhật một số tiêu đề của một ứng dụng wsgi trong quá trình xử lý lỗi. – Eric

3

Từ cách sử dụng của bạn, có vẻ như bạn thực sự muốn sử dụng từ điển để bắt đầu, không phải danh sách các bộ dữ liệu. Nếu bạn đang xử lý trường đầu tiên của mỗi tuple như là một khóa duy nhất, làm cho nó trở thành một từ điển để bạn có được O (1) truy cập và xác nhận rằng các khóa thực sự là duy nhất.

Nếu không, bạn cần phải tìm kiếm để tìm chỉ mục của bộ sửa đổi, và sau đó ghi đè vị trí đó trong mảng bằng một bộ mới, vì bản thân bộ tuple không thể sửa đổi được.

index = -1 
target = "b" 
new_value = "friend" 
for i, v in enumerate(foo): 
    if v[0] == target: 
    index = i 
    break 
if index >= 0: 
    foo[index] = (foo[index][0], new_value) 

Điều này, được thừa nhận, hơi vụng về nhưng không thẳng về phía trước và ít nhất phải nhanh hơn một chút (và ít bộ nhớ đói) hơn giải pháp hiện tại của bạn. Nó có thể tầm thường được bao bọc thành một chức năng để gói gọn nó, tất nhiên.

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