如何打乱 python 列表以便保留某些元素的出现?

How to shuffle a python list such that the occurrence of some elements are preserved?

我从一个整数列表开始:

A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]

洗牌后,我希望一些元素(比如 3、4 和 5)保留它们在 A 中出现的顺序,而其余元素可以自由随机洗牌。类似于:

结果#1: A = [ 5, 2, 3, 1, 8, 4, 6, 7 ]

-或-

结果 #2: A = [ 7, 5, 6, 1, 3, 4, 8, 2 ]

-但不是-

结果 #3(无效结果) A = [7, 4, 6, 1, 3, 5, 8, 2]

感谢所有建议!

这是一种使用 random 模块的方法

例如:

import random

A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]
result = A[2:5]
del A[2:5]
while A:
    l = len(A)
    result.insert(random.randint(0, l), A.pop(random.randrange(l)))
print(result)

演示

def rand_shfl(lst):
    result = lst[2:5]
    del lst[2:5]
    while A:
        l = len(A)
        result.insert(random.randint(0, l), A.pop(random.randrange(l)))
    return result

for _ in range(10):
    A = [ 1, 2, 5, 3, 4, 6, 7, 8 ]
    print((rand_shfl(A)))

输出:

[1, 7, 6, 5, 8, 3, 4, 2]
[8, 1, 2, 7, 5, 3, 6, 4]
[8, 6, 7, 2, 1, 5, 3, 4]
[1, 7, 2, 8, 5, 3, 4, 6]
[6, 8, 7, 5, 1, 3, 4, 2]
[7, 2, 5, 6, 1, 3, 4, 8]
[1, 8, 5, 2, 3, 4, 6, 7]
[5, 7, 1, 6, 3, 8, 4, 2]
[1, 5, 7, 3, 2, 4, 8, 6]
[8, 2, 7, 6, 5, 3, 4, 1]

提取您要保持相对顺序的元素,正常洗牌,然后通过随机选择要插入的“保留”元素的索引将列表粘在一起。如果你使用集合来加速 in 操作,所有操作都是线性的,我没有费心。 keep 列表的顺序很重要。

>>> import random
>>> L = [1, 2, 5, 3, 4, 6, 7, 8]
>>> keep = [2, 3, 4]
>>> kept = [L[i] for i in keep][::-1]
>>> unkept = [x for i, x in enumerate(L) if i not in keep]
>>> random.shuffle(unkept)
>>> idxes = random.sample(list(range(len(L))), k=len(keep))
>>> result = [kept.pop() if i in idxes else unkept.pop() for i in range(len(L))]
>>> result
[6, 5, 3, 8, 4, 1, 7, 2]

随机测试:

import random

def shuffle_with_fixed_order(L, keep):
    kept = [L[i] for i in keep][::-1]
    unkept = [x for i, x in enumerate(L) if i not in keep]
    random.shuffle(unkept)
    idxes = random.sample(list(range(len(L))), k=len(keep))
    return [kept.pop() if i in idxes else unkept.pop() for i in range(len(L))]
    
if __name__ == "__main__":
    for _ in range(5000):
        L = list(range(50))
        random.shuffle(L)
        keep = sorted(random.sample(L, k=20))
        shuffled = shuffle_with_fixed_order(L, keep)
        new_locs = [shuffled.index(L[i]) for i in keep]
        assert all(x < y for x, y in zip(new_locs, new_locs[1:]))

以下可能适合您

import random
lst=[1, 2, 5, 3, 4, 6, 7, 8]
s_lst = {5:0,3:0,4:0}

idx_lst = [random.randint(0, len(lst)) for i in range(len(s_lst))]
idx_lst.sort()

for i, s in enumerate(s_lst.keys()):
    s_lst[s] = idx_lst[i]
    lst.remove(s)

random.shuffle(lst)
for k, v in s_lst.items():
    lst.insert(v, k)

print(lst)