Python 如何随机排列对象列表的切片或子集?
考虑对象列表上的Python 如何随机排列对象列表的切片或子集?,python,shuffle,slice,sublist,Python,Shuffle,Slice,Sublist,考虑对象列表上的random.shuffle(即非int等基本类型)。 我说的是任何一般的对象;下面的数字只是一个例子 由于random.shuffle在适当的位置执行操作,并且不返回任何值,因此对该列表的某个片段或子集进行无序移动会有点笨拙。 对于一个片段(或子集),有没有比获取片段(或deepcopy)、洗牌它然后用结果覆盖原始列表片段更好的方法?i、 e.情况如下: import copy import random class SomeNumber(object): # just a
random.shuffle
(即非int等基本类型)。
我说的是任何一般的对象;下面的数字只是一个例子
由于random.shuffle在适当的位置执行操作,并且不返回任何值,因此对该列表的某个片段或子集进行无序移动会有点笨拙。
对于一个片段(或子集),有没有比获取片段(或deepcopy)、洗牌它然后用结果覆盖原始列表片段更好的方法?i、 e.情况如下:
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
再考虑一个更一般的情况,在这个情况下,我可能希望传递一个布尔向量,其中的元素将被包括在洗牌中。然后提取该子集,将其洗牌并重新插入。你能找到一个好的成语吗
PS@ReutSharabani建议如下:
def partial_shuffle(lst, imin, imax):
lst[imin:imax] = sorted(lst[imin:imax], key=lambda x: random.random())
return lst
如图所示:
它使用sorted
作为洗牌(根据随机键排序),但是我不确定它是否真的是随机的
您可以创建一个混洗函数来返回列表的混洗副本:
#!/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])
如果您想洗牌原始列表的一部分,为什么要使用深度副本?你就不能切->洗牌->回写吗?@ReutSharabani:对。我更新了问题。但是有更好的成语吗?考虑更一般的情况下,我们通过布尔向量的洗牌/保持,在底部提到。最好的习惯用法是什么?如果你的意思是alecxe的回答提到可选的第二个arg
random.shuffle(x[,random])
,其中random是一个0参数函数,返回[0.0,1.0]中的随机浮点;(默认情况下,这是函数random()。使用该选项的代码肯定会更加笨拙。我的错,我指的是答案…出于某种原因,我认为它不是选定的答案。请参阅我发布的答案。因此:def partial_shuffle(lst,imin,imax):lst[imin:imax]=sorted(lst[imin:imax],key=lambda x:random.random())return lst
您可以编写一个shuffle函数,使用random.shuffle
返回被洗牌的列表,这可能就是我要做的…在洗牌之前一定要复制列表(您可以使用l[:]
),这正是这个问题要求您做的;-)代码在哪里?我对你的代码忠贞不渝。如果你使用它一次,也许一个函数是一个多余的……我会把它添加进去……见我的答案的底部,我也要求一个统一的实现,同时考虑更一般的情况,在这里我想传递一个布尔向量,其中哪些元素将被包含在洗牌中。
#!/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])