Поскольку dict() сортируется в соответствии с внутренними хэшами, используемыми для быстрого доступа, а не по порядку, в котором вы добавили к нему элементы, вы можете считать его случайным и использовать dict.popitem().
Но popitem() также удалит этот элемент из словаря. Поэтому вы, возможно, захотите использовать:
d = {...}
keys = d.keys()
item = keys.pop(0)
value = d[item]
вместо этого. Однако обратите внимание, что любой dict с одинаковыми/похожими ключами может иметь один и тот же порядок ключей.
Если вы хотите надлежащего случайного получения затем сделать:
import random
d = {"red": "#ff0000", "green": "#00ff00", "blue": "#0000ff", "black": "#000000", "white": "#ffffff"}
keys = d.keys()
item = random.choice(keys)
value = d[item]
Конечно, если вы хотите, чтобы предотвратить повторение вам придется использовать дополнительные Dict() и в то время как цикл:
import random
d = {"red": "#ff0000", "green": "#00ff00", "blue": "#0000ff", "black": "#000000", "white": "#ffffff"}
keys = d.keys()
used = {}
def get_rand_item (d):
item = random.choice(keys)
while item in used:
item = random.choice(keys)
value = d[item]
used[item] = None
return item, value
get_rand_item(d)
Здесь Я использую dict как хранилище, потому что его поиск быстрее, чем список.
Вы запросили самый быстрый способ. : D
В то время как я в этом, давайте посмотрим, если я могу получить еще более быстрый способ получения случайных элементов без повторений:
from random import choice
class RandomGetter:
def __init__ (self, d, adapt=1):
self.keys = keys = d.keys()
if adapt:
# Could be done in place too
dct = {}
for k in keys:
dct[k] = (d[k], 0)
self.dct = dct
self.count = 1
else:
self.dct = d
# Assume all items have been visited
self.count = d[keys[0]][1]+1
self.visited = 0
self.length = len(self.dct)
def __len__ (self):
return self.length
def randitem (self, default=None):
if self.visited==self.length:
# After 'default' is returned (all items gotten),
# same RandomGetter() can be used again:
self.count += 1
self.visited = 0
return default
d = self.dct
kz = self.keys
c = self.count
key = choice(kz)
value, flag = d[key]
while flag>=c:
key = choice(kz)
value, flag = d[key]
d[key] = (value, flag+1)
self.visited += 1
return key, value
def next (self):
i = self.randitem()
if i==None: raise StopIteration
return i
def __iter__ (self):
while 1: yield self.next()
# Now testing:
# Lets create a dictionary of one million items:
d = dict.fromkeys(xrange(1000000))
# This takes about 0.128 seconds
# Now, lets initialize Rg
r = RandomGetter(d)
# If dict is not prepared in advance, as this one isn't we use adapt=1 and it takes
# about 8.92 seconds. Yack!
# Now measure time for each random getting:
from time import time
def check():
randitem = r.randitem # Faster access to the method
e = []
for _ in xrange(len(r)):
t = time()
randitem()
e.append(time()-t)
print "Total/min/max/med/avg/(0 time count)"
e.sort()
s = sum(e)
if len(r)%2==0: m = (e[len(r)/2]+e[len(r)/2+1])/2
else: m = e[len(r)/2+1]
print s, e[0], e[-1], m, ("%.15f" % (s/1000000)), e.count(0.0)
check()
# It yields following results on my machine:
# About 25.224 seconds to randomly get all 1000000 items
# Minimal time needed is not measurable using this technique so it is 0.0
# Maximal time needed to get an item is about 1.678 seconds
# Median results with 0.0, thus we know that more than half randomly gotten items took practically no time
# In fact, there are about 998808 items with getting time of 0.0 seconds
# Average getting time is about 0.000025224 seconds
# By examining results closely I deduced that only last few items took a long time to get them.
# All in all, not bad for one million items, in my opinion anyway.
# For dict of 2000 items, total time was 0.016 and that was also the maximal value and it was for the last gotten item
# Time didn't cross one second until length of a given dictionary wasn't bigger than 100000
# If you want, you can run my code through timeit to recheck, but it seems that it is faster
# than suggested random dictionary.
https://docs.python.org/3/library/stdtypes.html#dict.popitem – n1c9
Рассматривали ли вы 'next (iter (dct))'? – vaultah
Вот хороший фрагмент кода, который делает именно это, но с временной сложностью O (1). Поскольку вы беспокоитесь о времени, вам может быть лучше использовать это - https://github.com/robtandy/randomdict – SRC