简体   繁体   English

从列表中随机选择至少一次

[英]Random choice from list at least once

I have 10 elements in a Python list. 我在Python列表中有10个元素。 I want to select an item randomly from this list - multiple times (more than 1000 times...). 我想从此列表中随机选择一个项目-多次(超过1000次...)。 And, I want to ensure that all 10 are elements chosen at least once. 而且,我想确保所有10个元素至少被选择一次。 Is there a way to do it in Python? 有没有办法在Python中做到这一点?

random.choice is not helping me...(or, at least, I do not know how to use it). random.choice并不能帮助我...(或者至少我不知道如何使用它)。

As I mentioned in a comment, if it's truly random, and it iterates a set number of times, it is not 100% certain all items are chosen at least once, though if you are doing it over 1000 times on a list of 10 items, it's of course highly probably they will be. 正如我在评论中提到的那样,如果它确实是随机的,并且会重复设置一定的次数,则不是100%确定所有项目至少被选中一次,尽管如果您在10个项目的列表中进行了1000次以上,当然很可能会。 To make 100% sure all items are chosen once, you'd have to impose some kind of rule that would preclude complete randomness. 为了确保100%确保所有项目都被选中一次,您必须施加某种规则来排除完全随机性。 BUT if you didn't want to do that, you could set your minimum number of random selections, and if for some reason all elements had not been selected, it would keep going until they are. 但是,如果您不想这样做,则可以设置最小随机选择数,并且如果由于某种原因未选择所有元素,它将一直进行到选择为止。

import random
original_list = [1,2,3,4,5,6,7,8,9,10]
list = original_list[:]
minimum_iterations = 1000

while minimum_iterations > 0:  
    choice = random.choice(list)
    print(choice)
    if choice in original_list:
        original_list.remove(choice)
    minimum_iterations = minimum_iterations - 1

while len(original_list) > 0: # only executes if items remain unchosen
    choice = random.choice(list)
    print(choice)
    if choice in original_list:
        original_list.remove(choice)

This again is not completely random, since it's continuing until every item is chosen ; 这又不是完全随机的,因为它一直持续到选择了每个项目为止。 but it's the most random way I can think of to accomplish your original question. 但这是我想到的最随机的方式来完成您的原始问题。

Another solution, if you were willing to "distribute" the randomness a little more, would be to have it randomly select each list value once until all were selected, then continue doing so for the total number of iterations. 如果您愿意多一点“分布”随机性,另一种解决方案是让它随机选择每个列表值一次,直到全部被选中,然后继续进行迭代的总数。 That would guarantee each value is chosen an equal number of times, but in an order that is random. 这将确保每个值被选择相等的次数,但是顺序是随机的。

You could start by cloning the list, ensuring each is in the new list at least once, which simulates choosing with probability 1 for at least one each. 您可以从克隆列表开始,确保每个列表至少出现在新列表中一次,这模拟了至少每个出现概率为1的选择。

Then you use random.choice in a range loop to randomly choose your_number of times from the list. 然后,在范围循环中使用random.choice从列表中随机选择your_number次。

import random

your_number = 1000
old_list = [1,2,3,4,5,6,7,8,9,10]
new_list = list(old_list)

for x in range(your_number):
    new_list.append(random.choice(old_list))

if you don't like the numbers being in predictable locations, increase the entropy by using random.shuffle like so: 如果您不希望数字位于可预测的位置,请使用random.shuffle来增加熵,如下所示:

random.shuffle(new_list)

Moving my answer from the comments to a post. 将我的答案从评论移到帖子。

statistically, if you iterate over an array with ten elements a thousand times, each element will get chosen once. 从统计上讲,如果您对具有十个元素的数组进行一千次迭代,则每个元素将被选择一次。 So why not just do something like this? 那么,为什么不做这样的事情呢? with a correction after the expensive operation to ensure presence. 在进行昂贵的操作后进行校正以确保存在。

import random

data = range(10) # or really any iterable sequence
occurences = {}

for i in range(1000):
    choice = random.choice(data)

    # increment the occurence of the random choice by one
    # if the random choice was not found assume 0
    occurences[choice] = occurences.get(choice, 0) + 1

# error correction to ensure each element is counted once
# keep in mind this is extremely unlikely.

# iterate over each element in data that is not a key in occurences
for forgotten in (item for item in data if item not in occurences):
    choice = random.choice(tuple(data.keys()))

    # ensure each data element has been counted once
    # so simply borrow from another occurence
    occurences[choice] -= 1
    occurences[forgotten] = 1

Use a set to keep track of what items have been used; 使用一组来跟踪已使用的项目; re-roll if not all are used in the set. 如果未在集合中全部使用,请重新滚动。

The amortized cost is negligible (as the odds to failing are very low) and the added tracking is O(1), so it doesn't change the O(n) time complexity. 摊销成本可忽略不计(因为失败的机率非常低),并且增加的跟踪为O(1),因此它不会改变O(n)的时间复杂度。

It is not truly random, but the internal randomness of the set is maintained and it guarantees as random a result as you can get while guaranteeing all ten terms. 它不是真正的随机性,但集的内部随机性得以保留,它可以保证在保证所有十项的同时获得尽可能随机的结果。

opts = range(10)  # or your list
result = []
while len(set(result)) != len(opts):
    for _ in range(1000):
        choice = random.choice(opts)
        result.append(choice)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM