如何random.shuffle切片或对象列表的子集?

时间:2014-12-07 14:59:05

标签: python shuffle slice sublist

在对象列表上考虑random.shuffle(即不是像int这样的原始类型)。 我在谈论任何一般的对象;以下数字只是一个例子。

由于random.shuffle就地行动并返回None,这使得对该列表的切片或子集进行洗牌有点笨拙。 对于切片(或子集),有没有比采用切片(或深度复制),改组,然后用结果覆盖原始列表切片更好的方法?即如下:

import copy
import random

class SomeNumber(object): # just a stupid class to illustrate the point
    def __init__(self, n):
        self.n = n
    def __repr__(self):
        return str(self.n)

ll = [ SomeNumber(i) for i in range(6) ]
# [0, 1, 2, 3, 4, 5]

# Say we want to shuffle slice 2:end
#ld = copy.deepcopy(ll[2:])
ld = ll[2:]
# [2, 3, 4, 5]
random.shuffle(ld)
# [3, 2, 4, 5]

# ll didn't get shuffled though, so must overwrite the original slice...
ll[2:] = ld
# [0, 1, 5, 3, 4, 2]

del ld

还考虑更常见的情况,我可能想要传递一个布尔向量,其中哪些元素将包含在shuffle中。然后提取该子集,将其洗牌并重新插入。你能找到一个好习语吗?

PS @ReutSharabani建议如下:

def partial_shuffle(lst, imin, imax):
    lst[imin:imax] = sorted(lst[imin:imax], key=lambda x: random.random())
    return lst

1 个答案:

答案 0 :(得分:1)

如上所示:Why does random.shuffle return None?

#!/usr/bin/env python

import copy
import  random

class SomeNumber(object): # just a stupid class to illustrate the point
    def __init__(self, n):
        self.n = n
    def __repr__(self):
        return str(self.n)

ll = [ SomeNumber(i) for i in range(6) ]
print ll

ll[2:] = sorted(ll[2:], key=lambda x: random.random())

print ll

它使用sorted 行为作为随机播放(根据随机键排序),但我不确定是否非常随意。

您可以创建一个shuffle函数来返回列表的混洗副本:

#!/usr/bin/env python
import random
# the function
def shuffle(ll, include_list=None):
    if not include_list:
        include_list = [True] * len(ll)
    # tag the list (default: all, for use of slices) and shuffle
    tagged_list = [x for x in zip(include_list, ll)]
    shuffle_list = [x for x in tagged_list if x[0]]
    random.shuffle(shuffle_list)

    # re-insert to tagged list by false tags, enumerate indices changed
    false_indices = sum(map(lambda x: [x[0]] if x[1][0] else [], enumerate(tagged_list)), [])
    for shuffle_index, tagged_index in enumerate(false_indices):
        tagged_list[tagged_index] = shuffle_list[shuffle_index]
    # return only the values
    return [x[1] for x in tagged_list]

# now use it whenever you want to shuffle something

l = [1, 2, 3, 4, 5]
print "shuffeled: %s" % shuffle(l)
# original list stays the same (not in-place)
print "original: %s" % l
# now to shuffle a part of a list you can:

print "shuffeled (2+): %s" % shuffle(l[2:])

# with a boolean filter list:
print "shuffle indices 0, 2, 4: %s " % shuffle(l, [True, False, True, False, True])