我试图将第3个列表中的元素随机播放到最后一个位置,这样前两个将始终保持不变 e.g。
list = ['a?','b','c','d','e']
到
list = ['a?','b','d','e','c']
由于某种原因,这不起作用:
list = ['a?','b','c','d','e']
import random
random.shuffle(list[2:])
print list
任何人都知道我做错了什么?
对我来说唯一有用的是迄今为止(EDITED):
lists = [['a?','b','c','d','e'],['1?','2','3','4','5','6','7']]
import random
for list in lists:
copy = list[2:]
random.shuffle(copy)
list[2:] = copy
print lists
认为这正是我所需要的。
答案 0 :(得分:7)
你做的是这个:
copy = list[2:]
random.shuffle(copy)
对原始列表没有太大作用。试试这个:
copy = list[2:]
random.shuffle(copy)
list[2:] = copy # overwrite the original
答案 1 :(得分:7)
如果你想在不复制的情况下进行随机播放,你可以尝试编写自己的可变切片类,如下所示(这是一个粗略的实现草图,没有边界检查等):
class MutableSlice(object):
def __init__(self, baselist, begin, end=None):
self._base = baselist
self._begin = begin
self._end = len(baselist) if end is None else end
def __len__(self):
return self._end - self._begin
def __getitem__(self, i):
return self._base[self._begin + i]
def __setitem__(self, i, val):
self._base[i + self._begin] = val
然后将原始列表包装到其中并输入标准shuffle:
>>> mylist = [1,2,3,4,5,6]
>>> slice = MutableSlice(mylist, 2)
>>> import random
>>> random.shuffle(slice)
>>> mylist
[1, 2, 4, 3, 5, 6]
答案 2 :(得分:5)
您可以创建自己的随机播放功能,允许您在可变序列中随机播放切片。它处理切片副本的采样并重新分配回切片。您必须传递slice()
个参数,而不是更熟悉的[2:]
符号。
from random import sample
def myShuffle(x, *s):
x[slice(*s)] = sample(x[slice(*s)], len(x[slice(*s)]))
用法:
>>> lst = ['a?','b','c','d','e'] #don't use list as a name
>>> myShuffle(lst, 2) #shuffles lst[:2]
>>> lst
['b', 'a?', 'c', 'd', 'e']
>>> myShuffle(lst, 2, None) #shuffles lst[2:]
>>> lst
['b', 'a?', 'd', 'e', 'c']
答案 3 :(得分:2)
l[2:]
构建了一个新列表,random.shuffle
尝试“就地”更改列表,这对l
本身没有任何影响。
您可以使用random.sample
:
l[2:] = random.sample(l[2:], len(l)-2)
答案 4 :(得分:2)
要对列表中的一部分进行随机播放,没有副本,我们可以使用Knuth shuffle:
import random
def shuffle_slice(a, start, stop):
i = start
while (i < stop-1):
idx = random.randrange(i, stop)
a[i], a[idx] = a[idx], a[i]
i += 1
它与random.shuffle完全相同,除了在切片上:
>>> a = [0, 1, 2, 3, 4, 5]
>>> shuffle_slice(a, 0, 3)
>>> a
[2, 0, 1, 3, 4, 5]
答案 5 :(得分:1)
使用列表快速删除的事实 并插入和退出以前的解决方案 (https://stackoverflow.com/a/25229111/3449962):
列出项目
这将使用具有依赖的内存开销的就地操作 列表中固定元素的数量。线性时间。有可能 更一般的shuffle_subset实现:
#!/usr/bin/env python
"""Shuffle elements in a list, except for a sub-set of the elments.
The sub-set are those elements that should retain their position in
the list. Some example usage:
>>> from collections import namedtuple
>>> class CAnswer(namedtuple("CAnswer","x fixed")):
... def __bool__(self):
... return self.fixed is True
... __nonzero__ = __bool__ # For Python 2. Called by bool in Py2.
... def __repr__(self):
... return "<CA: {}>".format(self.x)
...
>>> val = [3, 2, 0, 1, 5, 9, 4]
>>> fix = [2, 5]
>>> lst = [CAnswer(v, i in fix) for i, v in enumerate(val)]
>>> print("Start ", 0, ": ", lst)
Start 0 : [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]
Using a predicate to filter.
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst, lambda x : x.fixed)
... print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst) # predicate = bool()
... print([lst[i] for i in fix], end=" ")
...
[<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>] [<CA: 0>, <CA: 9>]
Exclude certain postions from the shuffle. For example, exclude the
first two elements:
>>> fix = [0, 1]
>>> lst = [CAnswer(v, i in fix) for i, v in enumerate(val)]
>>> print("Start ", 0, ": ", lst)
Start 0 : [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst, fix)
... print([lst[i] for i in fix], end=" ")
...
[<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>]
Using a selector with the same number of elements as lst:
>>> fix = [0, 1]
>>> lst = [CAnswer(v, i in fix) for i, v in enumerate(val)]
>>> sel = [(i in fix) for i, _ in enumerate(val)]
>>> print("Start ", 0, ": ", lst)
Start 0 : [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... shuffle_subset(lst, sel)
... print([lst[i] for i in fix], end=" ")
...
[<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>]
A generator as selector works fine too:
>>> fix = [0, 1]
>>> lst = [CAnswer(v, i in fix) for i, v in enumerate(val)]
>>> print("Start ", 0, ": ", lst)
Start 0 : [<CA: 3>, <CA: 2>, <CA: 0>, <CA: 1>, <CA: 5>, <CA: 9>, <CA: 4>]
>>> for i in range(4): # doctest: +NORMALIZE_WHITESPACE
... sel = ((i in fix) for i, _ in enumerate(val))
... shuffle_subset(lst, sel)
... print([lst[i] for i in fix], end=" ")
...
[<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>] [<CA: 3>, <CA: 2>]
"""
from __future__ import print_function
import random
def shuffle_subset(lst, predicate=None):
"""All elements in lst, except a sub-set, are shuffled.
The predicate defines the sub-set of elements in lst that should
not be shuffled:
+ The predicate is a callable that returns True for fixed
elements, predicate(element) --> True or False.
+ If the predicate is None extract those elements where
bool(element) == True.
+ The predicate is an iterable that is True for fixed elements
or len(predicate) == len(lst).
+ The predicate is a list of indices of fixed elements in lst
with len(predicate) < len(lst).
"""
def extract_fixed_elements(pred, lst):
try:
if callable(pred) or pred is None:
pred = bool if pred is None else pred
fixed_subset = [(i, e) for i, e in enumerate(lst) if pred(e)]
elif (hasattr(pred, '__next__') or len(pred) == len(lst)):
fixed_subset = [(i, lst[i]) for i, p in enumerate(pred) if p]
elif len(pred) < len(lst):
fixed_subset = [(i, lst[i]) for i in pred]
else:
raise TypeError("Predicate {} not supported.".format(pred))
except TypeError as err:
raise TypeError("Predicate {} not supported. {}".format(pred, err))
return fixed_subset
#
fixed_subset = extract_fixed_elements(predicate, lst)
fixed_subset.reverse() # Delete fixed elements from high index to low.
for i, _ in fixed_subset:
del lst[i]
random.shuffle(lst)
fixed_subset.reverse() # Insert fixed elements from low index to high.
for i, e in fixed_subset:
lst.insert(i, e)
if __name__ == "__main__":
import doctest
doctest.testmod()
答案 6 :(得分:1)
我从random.shuffle中复制了shuffle函数并对其进行了调整,以便它只在定义的范围内对列表进行洗牌:
import random
a = range(0,20)
b = range(0,20)
def shuffle_slice(x, startIdx, endIdx):
for i in reversed(xrange(startIdx+1, endIdx)):
# pick an element in x[:i+1] with which to exchange x[i]
j = random.randint(startIdx, i)
x[i], x[j] = x[j], x[i]
#Shuffle from 5 until the end of a
shuffle_slice(a, 5, len(a))
print a
#Shuffle b from 5 ... 15
shuffle_slice(b, 5, 15)
print b
上面的代码仅对指定范围内的元素进行洗牌。随机播放,即没有创建列表的副本。
答案 7 :(得分:0)
试试这个..它更简单,不会制作列表的任何副本 只需使用列表索引即可修复任何元素。
工作:
创建一个仅包含您想要随机播放的元素的新列表。
随机播放新列表。
从原始列表中删除您想要随机播放的元素。
将新创建的列表插入适当索引的旧列表
import random list = ['a?', 'b', 'c', 'd', 'e'] v = [] p = [v.append(list[c]) for c in range(2,len(list))] #step 1 random.shuffle(v) #step 2 for c in range(2,len(list)): list.remove(list[c]) #step 3 list.insert(c,v[c-2]) #step 4 #c-2 since the part to be shuffled begins from this index of list print(list)