Pythonic способ доступа к произвольному элементу из словаря
У меня есть словарь, полный предметов. Я хочу заглянуть за один, произвольный элемент:
print "Amongst our dictionary items are such diverse elements as: %s" % arb(dictionary)
Мне все равно, какой предмет. Это не обязательно быть случайным.
Я могу думать о многих способах реализации этого, но все они кажутся расточительными. Я задаюсь вопросом, являются ли какие-либо предпочтительные идиомы в Python или (даже лучше), если я не хватает одного.
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
Я нахожусь в положении, когда производительность недостаточно критична, что это имеет значение (пока), поэтому меня можно обвинить в преждевременной оптимизации, но я пытаюсь улучшить свой стиль кодирования Python, поэтому, если есть понимал вариант, было бы неплохо принять его.
Ответы
Ответ 1
Аналогично вашему второму решению, но немного более очевидному, на мой взгляд:
return next(iter(dictionary.values()))
Это работает как в python 2, так и в python 3, но в python 2 более эффективно это делать:
return next(dictionary.itervalues())
Ответ 2
Избегая полного беспорядка values
/itervalues
/viewvalues
, это одинаково хорошо работает в Python2 или Python3
dictionary[next(iter(dictionary))]
если вы предпочитаете выражения генератора
next(dictionary[x] for x in dictionary)
Ответ 3
Я полагаю, что на этот вопрос был дан значительный ответ, но, надеюсь, это сравнение прольет некоторый свет на компромисс между чистым кодом и временем:
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))
Вот результаты:
('pop', 0.0021750926971435547)
('iter', 0.002003908157348633)
('list', 0.047267913818359375)
('insert', 0.0010859966278076172)
Кажется, что использование iterkeys только маргинально быстрее, чем всплывающий элемент и повторная вставка, но в 10 раз быстрее, чем создание списка и выбор из него случайного объекта.
Ответ 4
Почему бы не использовать random
?
import random
def arb(dictionary):
return random.choice(dictionary.values())
Это дает понять, что результат должен быть чисто произвольным, а не побочным эффектом реализации. Пока производительность не станет актуальной проблемой, всегда проявляйте ясность по скорости.
Позор, который dict_values не поддерживает индексирование, было бы неплохо, если бы вы могли перейти в представление значения.
Обновление: поскольку все настолько одержимы производительностью, вышеуказанная функция принимает < 120ms, чтобы возвращать случайное значение из dict 1 миллиона элементов. Опираясь на четкий код, это не удивительная производительность, которую он делает.