Select random element from python non-uniform dictionary

I have a python dictionary in which the values ​​are lists of integers:

key1 -> [1, 2, 3]
key2 -> [1, 2, 3, ... 17]
key3 -> [1, 2, 3, 4, 5]

I want to select a random tuple (key, val), where val is a random value from a list of values ​​(for example: key2, 8). Random selection should be uniform across all values, therefore, for example, this method is uneven:

random_key = random.choice(d.keys())
random_val = random.choice(d[random_key])

because lists do not have the same length. I know the list concatenation length, n, so my current approach is this:

idx = np.random.randint(n)
c = 0
found = False

for k in D:
    for v in D[k]:
        if c == idx:
            found = True
            do_something_with_val(k, v);
            break
        c += 1
    if found:
        break

My question is: is there a better / faster way to do this?

+4
source share
2 answers

You can try (in Python 3 - for Python 2, use iteritems()):

idx = random.randint(0, n)
for k, v in D.items():
    if idx < len(v):
        do_something_with_val(k, v[idx])
        break
    else:
        idx -= len(v)

:

def ref():
    idx = random.randint(0, n)
    c = 0
    found = False
    for k in D:
        for v in D[k]:
            if c == idx:
                found = True
                # do_something_with_val(k, v);
                break
            c += 1
        if found:
            break


def uut():
    idx = random.randint(0, n)
    for k, v in D.items():
        if idx < len(v):
            # do_something_with_val(k, v[idx])
            break
        else:
            idx -= len(v)


if __name__ == '__main__':
    print(timeit.timeit('ref()', setup="from __main__ import ref", number=1000))
    print(timeit.timeit('uut()', setup="from __main__ import uut", number=1000))

:

1.7672173159990052
0.011254642000494641

, D {'key2': [3, 4, 5], 'key1': [0, 1, 2]}, :

0,166851
1,166141
2,166269
3,167094
4,167130
5,166515
+2

- "" ...

import random


d = {1: [1, 2],
     2: [1, 2, 3, 4]}


values = [(k, v) for k, l in d.items() for v in l ]    
k,v = random.choice(values)
print (k, v)

, ... ;)

0

Source: https://habr.com/ru/post/1623639/


All Articles