在Python中只打乱列表中的特定元素而非所有元素

1 投票
2 回答
513 浏览
提问于 2025-04-18 00:40

假设我有以下这个列表:

F = ["A","B","C","D","E"]

现在我想把这个列表中的元素打乱一下,但只打乱从B到E的部分。A应该始终放在最前面。其他的部分可以随意打乱。

然后,稍后我想把几个列表合并成一个大列表,比如:

FA = [["A1","B1","B2","B3"]["A2","B2","B3","B4"]...]

如果这样做完了,我会选择其中一个列表,然后把里面的元素(除了"A")打乱一下。

我想不出解决办法... :(

2 个回答

2

我们其实是打乱了索引,而不是打乱值:

import random
def shuffle_except(lst, keep):
    # keep should be a list of the indexes that we want to keep fixed
    # can also be a range or a sum of range
    # keep = range(0, 2) + range(5, 8)
    keep = set(keep)

    start_indexes = [i for i in xrange(len(lst)) if i not in keep]
    end_indexes = [i for i in xrange(len(lst)) if i not in keep]
    # we shuffle end indexes
    random.shuffle(end_indexes)
    # for each element in start_indexes, we move the corresponding element of lst
    # to its counterpart in end_indexes
    for i in xrange(len(start_indexes)):
        start = start_indexes[i]
        end = end_indexes[i]
        lst[start], lst[end] = lst[end], lst[start]


a = range(20)
print a
print a[1], a[5], a[10], a[15]
shuffle_except(a, {1, 5, 10, 15})
print a
print a[1], a[5], a[10], a[15]

输出结果是:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
1 5 10 15
[7, 1, 3, 2, 9, 5, 13, 0, 16, 8, 10, 11, 18, 17, 12, 15, 4, 6, 14, 19]
1 5 10 15

如你所见,除了我们指定的那些元素,其他的元素都已经被打乱了。

如果你还想要把多个打乱组合在一起,这里有个例子:

multi_list = [range(10) for _ in xrange(5)]
keep = {0, 3, 5}

for lst in multi_list:
    shuffle_except(lst, keep)

print multi_list

这是结果:

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

再次可以看到,列0、3和5的值和原始列表中的值完全一样。

3

使用 random.shuffle() 的源代码:

from random import randrange

def random_shuffle(x, fixed_indexes):
    for i in reversed(range(1, len(x))): # from random.shuffle() source code
        if i not in fixed_indexes:
           # pick an element in x[:i+1] with which to exchange x[i]
           while True:
               j = randrange(i+1)
               if j not in fixed_indexes:
                  break
           # swap
           x[i], x[j] = x[j], x[i]

示例:

>>> F = ["A", "B", "C", "D", "E"]
>>> random_shuffle(F, set([0]))
>>> F
['A', 'E', 'C', 'B', 'D']

撰写回答