Вот несколько решений.
Первый алгоритм поддерживает индекс idx
в последовательности и по каждому вызову idx
случайным образом модифицируется на другой индекс, поэтому невозможно, чтобы полученное значение было равным предыдущему значению.
from random import randrange
from itertools import islice
from collections import Counter
def non_repeating(seq):
m = len(seq)
idx = randrange(0, m)
while True:
yield seq[idx]
idx = (idx + randrange(1, m)) % m
seq = [1, 2, 3, 4]
print(''.join(map(str, islice(non_repeating(seq), 60))))
ctr = Counter(islice(non_repeating(seq), 12000))
print(ctr)
типичный выход
313231412323431321312312131413242424121414314243432414241413
Counter({1: 3017, 4: 3012, 3: 2993, 2: 2978})
Распределение значений, полученных с помощью этого кода выглядит довольно однороден, но я не анализировал ее математически, и я не делаю никаких гарантий в отношении его однородности.
Следующий код более сложный, но он дает равномерное распределение. Повторные значения не отбрасываются, они временно добавляются в пул повторяющихся значений, и алгоритм пытается как можно скорее использовать значения в пуле. Если он не может найти подходящее значение в пуле, он генерирует новое случайное значение.
from random import choice
from itertools import islice
from collections import Counter
def non_repeating(seq):
pool = []
prev = None
while True:
p = set(pool).difference([prev])
if p:
current = p.pop()
pool.remove(current)
else:
current = choice(seq)
if current == prev:
pool.append(current)
continue
yield current
prev = current
seq = [1, 2, 3, 4]
print(''.join(map(str, islice(non_repeating(seq), 60))))
ctr = Counter(islice(non_repeating(seq), 12000))
print(ctr)
Типичный выход
142134314121212124343242324143123212323414131323434212124232
Counter({4: 3015, 2: 3005, 3: 3001, 1: 2979})
Если длина входной последовательности только 2 или 3 бассейна может быть довольно большой, но для более длинных последовательностей, как правило, она содержит только несколько значений.
Наконец, вот версия, которая дает точно равномерное распределение. Не пытайтесь использовать его во входной последовательности из 2 (или меньше) элементов, потому что это может застрять в бесконечном цикле; конечно, в любом случае есть только 2 решения для такой входной последовательности. :)
Я не горжусь этим довольно уродливым кодом, но, по крайней мере, он выполняет эту работу. Я создаю выходной список длиной 60, чтобы он хорошо вписывался на экран, но этот код не вызывает проблем с созданием гораздо больших последовательностей.
from random import shuffle
from itertools import groupby
from collections import Counter
def non_repeating(seq, copies=3):
seq = seq * copies
while True:
shuffle(seq)
result, pool = [], []
for k, g in groupby(seq):
result.append(k)
n = len(list(g)) - 1
if n:
pool.extend(n * [k])
for u in pool:
for i in range(len(result) - 1):
if result[i] != u != result[i + 1]:
result.insert(i+1, u)
break
else:
break
else:
return result
# Test that sequence doesn't contain repeats
def verify(seq):
return all(len(list(g)) == 1 for _, g in groupby(seq))
seq = [1, 2, 3, 4]
result = non_repeating(seq, 15)
print(''.join(map(str, result)))
print(verify(result))
print(Counter(result))
типичный выход
241413414241343212423232123241234123124342342141313414132313
True
Counter({1: 15, 2: 15, 3: 15, 4: 15})
'Однако что-то не work' <- Не могли бы вы объяснить, что вы имеете в виду здесь? Каков наблюдаемый результат? Какой результат вы хотели? Как они отличаются друг от друга? – inspectorG4dget
Номера не должны отображаться в строке. Поэтому в списке не должно быть [1,1]. Однако это так. Я думаю, seq_CG [-1] не берет последний из самых актуальных списков. – SDahm
'Номера не должны появляться в строке' предполагает, что' [1,1] 'не должен находиться в' randomList', который, согласно вашему коду, не будет. Помимо этого, я действительно не понимаю, где у вас проблемы – inspectorG4dget