Генерация случайных списков в запросе Python
Я хочу, чтобы моя программа принимала числа от 1 до X и случайным образом распределяла эти числа между числами X/2 списков Y раз. Я не хочу, чтобы число повторялось в течение одного шаффла, также я не хочу, чтобы списки повторялись вообще. Так что если есть список [1,2], то не должно быть другого списка, содержащего 1 или 2 в том же случайном порядке, и не должно быть другого [1,2] или [2,1] во всем результате.
Это то, что я придумал, однако он продолжает повторять цифры. Любая реклама?
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
numberslist = range(1,amount+1)
twos = []
thisshuffle = []
final = []
while len(final) < (amount/2)*times:
twos = []
thisshuffle = []
while len(twos) < 2:
if len(numberslist)!=0:
randomnumber = random.choice(numberslist)
if (randomnumber in twos) or (randomnumber in thisshuffle):
numberslist.remove(randomnumber)
else:
twos.append(randomnumber)
thisshuffle.append(randomnumber)
numberslist.remove(randomnumber)
else:
numberslist = range(1,amount+1)
if (twos or list(reversed(twos))) not in final:
final.append(twos)
k=0
for i in range(times): #this shit prints shit
print "%s:" % (i+1), final[k:k+amount/2]
print
k = k + amount/2
Shuffler()
Shuffler()
2 ответа
Как указал ccf, ваши требования не являются тривиальными. Еще несколько шагов, и вы получите генератор судоку:)
Я попробовал несколько решений, но они либо не давали случайного вывода, либо были довольно неэффективными. Решение Ccf ясно написано, но, похоже, та же проблема; он производит упорядоченный вывод (например, [1, 2], [1, 3], [1, 4], [1, 5], [1, 6]
).
@cff - не лучше ли использовать itertools.combination вместо itertools.permutations, чтобы избежать генерации повторений?
Вот "решение", которое очень похоже на ccf (тоже не дает случайного вывода):
import itertools
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
perms = list(itertools.combinations(rng, 2))
lst_single = []
lst_all = []
for p in perms:
if len(lst_all) >= times:
for i, lst in enumerate(lst_all):
print str(i+1) + ": ", lst
break
if len(lst_single) == amount/2:
lst_all.append(lst_single)
lst_single = []
elif p[0] < p[1]:
p = list(p)
lst_single.append(p)
Shuffler()
Выход
Numbers up to: 6
Number of shuffles: 3
1: [[1, 2], [1, 3], [1, 4]]
2: [[1, 6], [2, 3], [2, 4]]
3: [[2, 6], [3, 4], [3, 5]]
И вот немного хакерское решение, которое, кажется, дает желаемый результат, но неэффективно. Он опирается на набор для фильтрации нежелательных комбинаций, но все же тратит ресурсы, производя их в первую очередь.
import random
def Shuffler():
amount = int(raw_input("Numbers up to: "))
times = int(raw_input("Number of shuffles: "))
rng = range(1, amount+1)
final = []
lst_len = amount/2
combos_unique = set()
while len(combos_unique) < lst_len*times:
combo_rand = random.sample(rng, 2)
if combo_rand[0] < combo_rand[1]:
combos_unique.add(tuple(combo_rand))
tmp = []
for combo in combos_unique:
tmp.append(list(combo))
if len(tmp) >= lst_len:
final.append(tmp)
tmp = []
for i, lst in enumerate(final):
print str(i+1) + ": ", lst
Shuffler()
Выход
Numbers up to: 6
Number of shuffles: 3
1: [[2, 6], [4, 6], [5, 6]]
2: [[4, 5], [1, 3], [1, 6]]
3: [[3, 4], [2, 4], [3, 5]]
Вам не нужны повторяющиеся числа в одном случайном порядке и любой повторный список... и так далее. Это не простая задача. Плюс еще один факт, что уникальные наборы чисел являются фиксированными, которые не могут быть установлены слишком высоко. Например, если вы установите "Numbers до:" 5 и "Number of shuffles: " 20, то наверняка вы получите повторяющиеся числа.
Проблема с вашим кодом, я вижу, заключается в следующем операторе if:
if (twos or list(reversed(twos))) not in final:
final.append(twos)
(twos или list(полностью измененный (twos))) - это логическое ИЛИ, результатом является twos, потому что twos не является пустым. Я предлагаю вам изменить выражение if на:
if (twos not in final) and (list(reversed(twos)) not in final):
final.append(twos)
Следующий код (python 2.7x) использует перестановки и перемешивание для генерации списка номеров. Затем сделайте список уникальным (например, нет [1,2] и [2,1] в одном списке). затем разделите их на группы в зависимости от количества перемешиваний, указанных пользователем. Нажмите любую букву, скрипт выйдет. Надеюсь, поможет:
from itertools import permutations
from random import shuffle
def Shuffler():
try:
amount = input("Numbers up to: ")
p = list(permutations(range(1, amount + 1), 2))
p_uniq = [list(x) for x in p if x[::-1] in p and x[0]<=x[1]]
shuf_max = len(p_uniq) /(amount / 2)
times = shuf_max + 1 # set a higher value to trigger prompt
while times > shuf_max:
shuffle(p_uniq) # shuffle the unique list in place
times = input("Number of shuffles (MAX %s): " % (shuf_max))
else:
for i, group in enumerate(list(zip(*[iter(p_uniq[: (amount /2) * times + 1])]* (amount/2)))):
print "%i: " % (i + 1), list(group)
Shuffler()
except:
print 'quitting...'
Shuffler()
Выход:
Numbers up to: 10
Number of shuffles (MAX 9): 8
1: [[6, 7], [1, 9], [2, 5], [5, 9], [9, 10]]
2: [[1, 10], [3, 8], [4, 10], [8, 10], [1, 5]]
3: [[1, 4], [6, 8], [3, 6], [2, 4], [4, 7]]
4: [[2, 10], [5, 8], [3, 9], [1, 7], [4, 9]]
5: [[1, 2], [7, 9], [1, 3], [6, 9], [1, 6]]
6: [[2, 9], [4, 8], [3, 5], [8, 9], [7, 10]]
7: [[2, 7], [2, 3], [7, 8], [3, 7], [3, 10]]
8: [[3, 4], [2, 6], [5, 6], [5, 7], [4, 6]]
Numbers up to: