我有一个包含整数的列表,我想创建一个副本,以使重复的元素至少相距一定距离。我知道必须有“足够”的不同元素和足够长的“开始”列表,但是我想创建该副本或返回一条消息(对于该距离)是不可能的。
这是python的“可能”实现,但有时该程序会创建无限循环。
import random
out = []
pbs = [1, 2, 3, 1, 2, 3, 5, 8]
l = len(pbs)
step = 3
while l > 0:
pb = random.choice(pbs)
if pb in out:
lastindex = out[::-1].index(pb)
if (len(out) - lastindex) < step:
continue
pbs.remove(pb)
out.append(pb)
l += -1
print(out)
谢谢您的帮助。
答案 0 :(得分:0)
基于我目前对您的问题的理解:
(尚不确定如何命名操作;
使用“ takeEvery”作为占位符。
可能在某处有一个算法。)
def takeEvery(list, step):
out = []
for pb in pbs:
if pb in out:
lastindex = out.index(pb) # keeping 'out' in reverse
if lastindex < step: continue
out.insert(0, pb) # insert in reverse (easier search)
out.reverse()
return out
pbs = [1, 2, 3, 1, 2, 3, 5, 8]
step = 3
out = takeEvery(pbs, step)
print('Step:', step)
print('Original:', pbs)
print('Result: ', out)
答案 1 :(得分:0)
您可以尝试一种生成方法,只要满足约束条件,就将数字添加到结果中;如果没有可用的数字,则回溯。这样,您可以生成全部或仅单个排列(使用next
)。这种方法的问题在于,它根本不检查是否可以完全满足约束条件,即,如果找不到解决方案,则对于较长的列表,它可以运行很长时间...
import random, collections
def scramble(lst, step):
def backtrack(i, counts, pos):
if not any(counts.values()):
yield []
for x in sorted(counts, key=lambda x: random.random()):
if counts[x] > 0 and (not pos[x] or i - pos[x][-1] >= step):
counts[x] -= 1
pos[x].append(i)
for res in backtrack(i+1, counts, pos):
yield [x] + res
pos[x].pop()
counts[x] += 1
return backtrack(0, collections.Counter(lst), collections.defaultdict(list))
pbs = [1, 2, 3, 1, 2, 3, 5, 8]
# ~ pbs = [random.randint(1, 10) for _ in range(100)]
step = 4
for x in scramble(pbs, step):
print(x)
在这里sorted(counts, key=lambda x: random.random())
表示要测试的下一个数字是随机确定的。相反,您可能想使用key=lambda x: -counts[x]
首先测试最受限制的数字,或者使用key=lambda x: (-counts[x], random.random())
之类的组合。这样可以更快地找到结果,但随机性较低。
或者使用随机优化方法,交换成对的元素,并在有限数量的“代”中保留比上一个更好的结果。再次,这不会检查是否可以先验找到这样的解决方案,并且除上述之外,这只会生成一个解决方案,或者如果找不到任何解决方案,则会引发异常。
def score(lst, step):
pos = collections.defaultdict(list)
for i, x in enumerate(lst):
pos[x].append(i)
return sum(max(0, step - (b-a)) for p in pos.values() for a, b in zip(p, p[1:]))
def scramble(lst, step, max_iter=1000):
lst = list(lst)
random.shuffle(lst)
s = score(lst, step)
for i in range(max_iter):
lst2 = list(lst)
a, b = random.randrange(len(lst)), random.randrange(len(lst))
lst2[a], lst2[b] = lst2[b], lst2[a]
s2 = score(lst2, step)
if s2 == 0:
return lst2
elif s2 < s:
lst, s = lst2, s2
else:
raise StopIteration(f"No result found after {max_iter} iteration")