Вот способ сделать это для Python> = 3.6, используя random.choices , что позволяет выбирать из совокупности с весами.
Идея состоит в том, чтобы сгенерироватьномера по одному.Каждый раз, когда мы генерируем новое число, мы исключаем предыдущее, временно устанавливая его вес на ноль.Затем мы уменьшаем вес выбранного.
Как должным образом заметил @roganjosh, у нас возникает проблема в конце, когда у нас остается более одного экземпляра последнего значения - и это может быть очень часто, особенно при небольшом количестве значений и большомчисло повторений.
Я использовал решение, чтобы вставить эти значения обратно в список, где они не создают конфликт, с помощью функции short send_back
.
import random
def send_back(value, number, lst):
idx = len(lst)-2
for _ in range(number):
while lst[idx] == value or lst[idx-1] == value:
idx -= 1
lst.insert(idx, value)
def shuffle_without_doubles(nb_values, repeats):
population = list(range(nb_values))
weights = [repeats] * nb_values
out = []
prev = None
for i in range(nb_values * repeats):
if prev is not None:
# remove prev from the list of possible choices
# by turning its weight temporarily to zero
old_weight = weights[prev]
weights[prev] = 0
try:
chosen = random.choices(population, weights)[0]
except IndexError:
# We are here because all of our weights are 0,
# which means that all is left to choose from
# is old_weight times the previous value
send_back(prev, old_weight, out)
break
out.append(chosen)
weights[chosen] -= 1
if prev is not None:
# restore weight
weights[prev] = old_weight
prev = chosen
return out
print(shuffle_without_doubles(6, 12))
[5, 1, 3, 4, 3, 2, 1, 5, 3, 5, 2, 0, 5, 4, 3, 4, 5,
3, 4, 0, 4, 1, 0, 1, 5, 3, 0, 2, 3, 4, 1, 2, 4, 1,
0, 2, 0, 2, 5, 0, 2, 1, 0, 5, 2, 0, 5, 0, 3, 2, 1,
2, 1, 5, 1, 3, 5, 4, 2, 4, 0, 4, 2, 4, 0, 1, 3, 4,
5, 3, 1, 3]
Некоторая грубая синхронизация: генерация (shuffle_without_doubles(600, 1200))
занимает около 30 секунд, то есть 720000 значений.