Spaces:
Build error
Build error
| import random | |
| class RandomCycler: | |
| """ | |
| Creates an internal copy of a sequence and allows access to its items in a constrained random | |
| order. For a source sequence of n items and one or several consecutive queries of a total | |
| of m items, the following guarantees hold (one implies the other): | |
| - Each item will be returned between m // n and ((m - 1) // n) + 1 times. | |
| - Between two appearances of the same item, there may be at most 2 * (n - 1) other items. | |
| """ | |
| def __init__(self, source): | |
| if len(source) == 0: | |
| raise Exception("Can't create RandomCycler from an empty collection") | |
| self.all_items = list(source) | |
| self.next_items = [] | |
| def sample(self, count: int): | |
| shuffle = lambda l: random.sample(l, len(l)) | |
| out = [] | |
| while count > 0: | |
| if count >= len(self.all_items): | |
| out.extend(shuffle(list(self.all_items))) | |
| count -= len(self.all_items) | |
| continue | |
| n = min(count, len(self.next_items)) | |
| out.extend(self.next_items[:n]) | |
| count -= n | |
| self.next_items = self.next_items[n:] | |
| if len(self.next_items) == 0: | |
| self.next_items = shuffle(list(self.all_items)) | |
| return out | |
| def __next__(self): | |
| return self.sample(1)[0] | |