创建具有重复的重复元素的列表副本

时间:2020-07-29 13:56:45

标签: python list sorting

我有一个包含整数的列表,我想创建一个副本,以使重复的元素至少相距一定距离。我知道必须有“足够”的不同元素和足够长的“开始”列表,但是我想创建该副本或返回一条消息(对于该距离)是不可能的。

这是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)

谢谢您的帮助。

2 个答案:

答案 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")