【问题标题】:Select random element from "non uniform" python dictionary从“非统一”python字典中选择随机元素
【发布时间】:2016-01-10 09:31:47
【问题描述】:

我有一个 python 字典,其中的值是整数列表:

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

我想选择一个随机元组(key, val),其中 val 是值列表中的一个随机值(例如:key2, 8)。随机选择在所有值上必须是统一的,例如,这种方法是不统一的:

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

因为列表的长度不同。 我知道列表串联的长度 n,所以我目前的方法如下:

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

我的问题是:有没有更好/更快的方法来做到这一点?

【问题讨论】:

  • 您是否控制这些列表中的值设置?
  • 你知道列表的最大长度是多少吗?还是你无法控制?
  • 列表的最大长度是已知的并且不会改变。但是,列表中元素的分布确实发生了变化。例如:元素 5 可以从“key2”中删除,新元素 1 可以添加到“key3”,但列表的最大长度始终相同。

标签: python dictionary random


【解决方案1】:

您可以尝试(在 Python 3 中,对于 Python 2,使用 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

【讨论】:

  • 我认为应该是 idx
  • @Frost,我添加了速度测量。可以查一下吗?
  • 为了速度,iteritems() 而不是items() 是合适的。
  • @EOL 是的,你是对的!但我的 python3 示例。
  • 我尝试使用 python 2 使用 items()。我将使用 iteritems() 再试一次,并让您知道。
【解决方案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)

这种方法非常快,但占用更多内存... 玩得开心;)

【讨论】:

  • 其实dict有很多更新,所以我不得不重新计算values很多次,让它变慢。
  • @Frost 也许考虑不使用 dict 而是使用类似容器的“值”来满足您的需求?
猜你喜欢
  • 2015-01-09
  • 1970-01-01
  • 2015-02-09
  • 2014-07-28
  • 2014-06-19
  • 2015-05-25
  • 2016-04-14
  • 2020-04-04
  • 2013-09-16
相关资源
最近更新 更多