2012-05-15 33 views
22

Tôi có một từ điển, đầy đủ các mục. Tôi muốn xem qua một mục duy nhất, tùy ý:Cách Pythonic để truy cập phần tử tùy ý từ điển

print "Amongst our dictionary's items are such diverse elements as: %s" % arb(dictionary) 

Tôi không quan tâm mục nào. Nó không cần phải là ngẫu nhiên.

Tôi có thể nghĩ ra nhiều cách để thực hiện điều này, nhưng tất cả đều có vẻ lãng phí. Tôi tự hỏi nếu có bất kỳ thành ngữ ưa thích trong Python, hoặc (thậm chí tốt hơn) nếu tôi thiếu một.

def arb(dictionary): 
# Creates an entire list in memory. Could take a while. 
    return list(dictionary.values())[0] 

def arb(dictionary): 
# Creates an entire interator. An improvement. 
    for item in dictionary.itervalues(): 
     return item 

def arb(dictionary): 
# No iterator, but writes to the dictionary! Twice! 
    key, value = dictionary.popitem() 
    dictionary[key] = value 
    return value 

Tôi đang ở vị trí mà hiệu suất không đủ quan trọng, nhưng tôi có thể bị buộc tội tối ưu hóa sớm, nhưng tôi đang cố gắng cải thiện kiểu mã hóa Python của mình, vì vậy nếu có một biến thể dễ hiểu, nó sẽ là tốt để chấp nhận nó.

+7

Điều gì về 'dictionary.itervalues ​​(). Next()'? Điều đó ít nhất sẽ tốt hơn chức năng 'arb' thứ hai của bạn. – srgerg

+0

@sgerg Tôi sẽ gửi nhưng bạn tiếp tục. : D – jamylak

+0

Họ có cần các mục khác nhau trong toàn bộ cuộc gọi không?Tất cả những điều này sẽ trả lại cùng một mục ... –

Trả lời

26

Tương tự như giải pháp thứ hai của bạn, nhưng một chút rõ ràng hơn, theo ý kiến ​​của tôi:

return next(iter(dictionary.values())) 

này hoạt động trong python 2 cũng như trong python 3, nhưng trong python 2 đó là hiệu quả hơn để làm điều đó như thế này :

return next(dictionary.itervalues()) 
+0

Rõ ràng hơn rất nhiều trong quan điểm của tôi! – jamylak

+4

Cần lưu ý rằng điều này làm tăng StopIteration nếu dict là trống rỗng. – yak

+5

Nhưng nếu bạn muốn tránh 'StopIteration', bạn có thể chỉ định giá trị mặc định, ví dụ: 'next (dictionary.itervalues ​​(), None)'. –

1

Tại sao không sử dụng random?

import random 

def arb(dictionary): 
    return random.choice(dictionary.values()) 

Điều này cho thấy rõ ràng rằng kết quả có ý nghĩa hoàn toàn tùy ý và không phải là tác dụng phụ thực hiện. Cho đến khi hiệu suất trở thành một vấn đề thực tế, luôn luôn đi với sự rõ ràng hơn tốc độ.

Thật đáng tiếc là dict_values ​​không hỗ trợ lập chỉ mục, thay vào đó, sẽ tốt hơn nếu có thể chuyển sang chế độ xem giá trị.

Cập nhật: vì mọi người đều bị ám ảnh với hiệu suất, hàm trên mất < 120ms để trả lại giá trị ngẫu nhiên từ một mệnh đề 1 triệu mục. Dựa vào mã rõ ràng không phải là hiệu suất tuyệt vời hit nó đang được thực hiện được.

+2

Trường hợp nó đã được chỉ định rằng các yếu tố được chọn không cần phải là ngẫu nhiên, đây là một sự lãng phí thời gian. Một docstring (và tên!) Là hoàn toàn đủ cho các quan sát như vậy. –

+1

Nếu tên là 'tùy ý' và hành động là lặp qua các khóa, tên đó sẽ không rõ ràng đối với tôi, do đó, có, một docstring là cần thiết. Nếu bạn phải viết một docstring để giải thích tại sao mã của bạn đang làm một cái gì đó khác với nó xuất hiện, có thể câu trả lời là viết mã rõ ràng hơn. –

+1

120 ms hoàn toàn không được chấp nhận đối với một thao tác như thế này. Điều này sẽ kết thúc trong một micro giây. Bạn đặt nó vào nơi bạn đã sử dụng 'd [next (iter (d))]' và ứng dụng của bạn có thể chậm hơn gấp hàng triệu lần. – user2357112

10

Tránh toàn bộ values/itervalues/viewvalues mớ hỗn độn, công trình này tốt như nhau trong python2 hoặc Python3

dictionary[next(iter(dictionary))] 

cách khác nếu bạn thích tạo ra cụm từ

next(dictionary[x] for x in dictionary) 
+0

bạn chỉ đơn giản là có thể làm 'tiếp theo (iter (dictionary.values ​​()))' –

+0

@ Ev.Kounis, nhưng trong python2, tạo ra một danh sách bổ sung. –

+0

'map' cũng tạo danh sách bằng Python 2. – user2357112

2

Tôi tin rằng câu hỏi đã được trả lời rõ rệt nhưng hy vọng sự so sánh này sẽ làm sáng tỏ một chút về mã sạch và thời gian giao dịch tắt:

from timeit import timeit 
from random import choice 
A = {x:[y for y in range(100)] for x in range(1000)} 
def test_pop(): 
    k, v= A.popitem() 
    A[k] = v 

def test_iter(): k = next(A.iterkeys()) 

def test_list(): k = choice(A.keys()) 

def test_insert(): A[0] = 0 

if __name__ == '__main__': 
    print('pop', timeit("test_pop()", setup="from __main__ import test_pop", number=10000)) 
    print('iter', timeit("test_iter()", setup="from __main__ import test_iter", number=10000)) 
    print('list', timeit("test_list()", setup="from __main__ import test_list", number=10000)) 
    print('insert', timeit("test_insert()", setup="from __main__ import test_insert", number=10000)) 

Dưới đây là kết quả:

('pop', 0.0021750926971435547) 
('iter', 0.002003908157348633) 
('list', 0.047267913818359375) 
('insert', 0.0010859966278076172) 

Có vẻ như rằng việc sử dụng iterkeys chỉ biên nhanh hơn sau đó poping một mục và tái chèn nhưng của 10x nhanh hơn sau đó tạo danh sách và chọn một đối tượng ngẫu nhiên từ nó.

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