改组对象列表


770

我有一个对象列表,我想对其进行洗牌。我以为可以使用该random.shuffle方法,但是当列表中包含对象时,这似乎失败了。是否有一种用于改组对象的方法或解决此问题的另一种方法?

import random

class A:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1, a2]

print(random.shuffle(b))

这将失败。


6
您能否举一个例子,说明它如何失败?random.shuffle应该不影响列表中对象的类型。
拜耳,2009年

3
>>> a1 = a()>>> a2 = a()>>> b = [a1,a2] >>> b [<__ main __。0xb7df9e6c处的实例,<__ main __。0xb7df9e2c处的实例>]> >>打印random.shuffle(b)无
-utdiscant

135
如下所述,random.shuffle不会返回新的混洗列表。它将列表拖拉到位。因此,您不应说“ print random.shuffle(b)”,而应在一行上进行洗牌,而在下一行上打印b。
Eli Courtwright 09年

如果您想改组numpy数组,请参见下面的答案。
Gordon Bean

1
有没有不改变原始数组但返回新的改组数组的选项?
查理·帕克

Answers:


1241

random.shuffle应该管用。这是一个示例,其中对象是列表:

from random import shuffle
x = [[i] for i in range(10)]
shuffle(x)

# print(x)  gives  [[9], [2], [7], [0], [4], [5], [3], [1], [8], [6]]
# of course your results will vary

请注意,随机播放在适当的地方起作用,并返回None。


1
@seokhoonlee都没有。它是一个pseduo随机数生成器,在可能的情况下,它由来自OS的真实随机性源作为种子。对于除密码学目的之外的所有内容,它都是随机的“足够”。这在random模块的文档中详细列出。
dimo414 '16

2
使用克隆创建新列表
Mohammad Mahdi KouchakYazdi

8
有没有不改变原始数组但返回新的改组数组的选项?
查理·帕克

5
@CharlieParker:我不知道。您可以使用random.sample(x, len(x))或仅复制一份shuffle。对于list.sort类似的问题,现在有list.sorted,但是没有类似的变体shuffle
tom10年

6
@seokhonlee用于加密安全随机性,请from random import SystemRandom改用;添加cryptorand = SystemRandom()第3行并将其更改为cryptorand.shuffle(x)
凌晨

115

当您了解到就地改组就是问题所在。我也经常遇到问题,而且似乎也常常忘记如何复制列表。使用sample(a, len(a))是解决方案,使用len(a)作为样本量。有关Python文档,请参见https://docs.python.org/3.6/library/random.html#random.sample

这是使用的简单版本random.sample(),它将经过改组的结果作为新列表返回。

import random

a = range(5)
b = random.sample(a, len(a))
print a, b, "two list same:", a == b
# print: [0, 1, 2, 3, 4] [2, 1, 3, 4, 0] two list same: False

# The function sample allows no duplicates.
# Result can be smaller but not larger than the input.
a = range(555)
b = random.sample(a, len(a))
print "no duplicates:", a == list(set(b))

try:
    random.sample(a, len(a) + 1)
except ValueError as e:
    print "Nope!", e

# print: no duplicates: True
# print: Nope! sample larger than population

有没有不改变原始数组但返回新的改组数组的选项?
查理·帕克

只需复制列表@CharlieParker:(old = [1,2,3,4,5]; new = list(old); random.shuffle(new); print(old); print(new)替换;换行)
fjsj

old[:]也可以进行浅表复制old

sample()对于数据分析的原型特别有用。sample(data, 2)用于设置管道的粘合代码,然后逐步对其进行“扩展”,直至len(data)
卡特琳·莱因韦伯

58

我也花了一些时间来做到这一点。但是洗牌的文档非常清楚:

列表随机排列x ; 不返回。

所以你不应该print(random.shuffle(b))。相反random.shuffle(b),然后print(b)


44
#!/usr/bin/python3

import random

s=list(range(5))
random.shuffle(s) # << shuffle before print or assignment
print(s)

# print: [2, 4, 1, 3, 0]

31

如果您碰巧已经使用numpy(在科学和金融应用中非常流行),则可以节省导入时间。

import numpy as np    
np.random.shuffle(b)
print(b)

http://docs.scipy.org/doc/numpy/reference/generation/numpy.random.shuffle.html


我喜欢这个答案的是,我可以控制numpy中的随机种子。我敢打赌,有一种方法可以在random模块中做到这一点,但现在对我而言这还不明显……这意味着我需要阅读更多内容。
VanBantam

25
>>> import random
>>> a = ['hi','world','cat','dog']
>>> random.shuffle(a,random.random)
>>> a
['hi', 'cat', 'dog', 'world']

这对我来说可以。确保设置随机方法。


仍然对我不起作用,请参阅已编辑问题中的示例代码。
utdiscant

4
第二个参数默认为random.random。完全忽略它是绝对安全的。
cbare 2015年

3
@alvas random.shuffle(a)不返回任何东西,即返回None。因此,您必须检查一个不返回值。
sonus21

15

如果您有多个列表,则可能要先定义排列(随机排列列表/重新排列列表中项目的方式),然后将其应用于所有列表:

import random

perm = list(range(len(list_one)))
random.shuffle(perm)
list_one = [list_one[index] for index in perm]
list_two = [list_two[index] for index in perm]

脾气暴躁

如果您的列表是numpy数组,则更为简单:

import numpy as np

perm = np.random.permutation(len(list_one))
list_one = list_one[perm]
list_two = list_two[perm]

处理器

我创建了mpu具有以下consistent_shuffle功能的小型实用程序包:

import mpu

# Necessary if you want consistent results
import random
random.seed(8)

# Define example lists
list_one = [1,2,3]
list_two = ['a', 'b', 'c']

# Call the function
list_one, list_two = mpu.consistent_shuffle(list_one, list_two)

请注意,它mpu.consistent_shuffle接受任意数量的参数。因此,您也可以使用它洗牌三个或更多列表。


10
from random import random
my_list = range(10)
shuffled_list = sorted(my_list, key=lambda x: random())

对于要交换订购功能的某些应用程序,此替代方法可能很有用。


另外,请注意,由于sorted,这是功能上的改组(如果您喜欢这种事情)。
Inaimathi

1
由于Timsort的稳定性,这并不是真正地随机分配值。(具有相同键的值按其原始顺序保留。)编辑:我想没关系,因为与64位浮点数发生冲突的风险非常小。
Mateen Ulhaq,

10

在某些情况下,使用numpy数组时,请random.shuffle在数组中使用创建的重复数据。

另一种方法是使用numpy.random.shuffle。如果您已经在使用numpy,那么这是优于generic的首选方法random.shuffle

numpy.random.shuffle

>>> import numpy as np
>>> import random

使用random.shuffle

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [1, 2, 3],
       [4, 5, 6]])

使用numpy.random.shuffle

>>> foo = np.array([[1,2,3],[4,5,6],[7,8,9]])
>>> foo

array([[1, 2, 3],
       [4, 5, 6],
       [7, 8, 9]])


>>> np.random.shuffle(foo)
>>> foo

array([[1, 2, 3],
       [7, 8, 9],
       [4, 5, 6]])

1
另外,numpy.random.permutation可能感兴趣:stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
Gordon Bean

使用random.shuffle时,是否有在数组中创建重复数据的示例?
nurettin

是的-它包含在我的答案中。请参阅标题为“示例”的部分。;)
Gordon Bean

没关系,我看到了三个要素,并认为是相同的。不错的发现
nurettin

1
random.shuffle文档应该
大声疾呼

10

对于单行代码,请使用random.sample(list_to_be_shuffled, length_of_the_list)示例:

import random
random.sample(list(range(10)), 10)

输出:[2、9、7、8、3、0、4、1、6、5]


6

当使用'foo'调用时,'print func(foo)'将输出'func'的返回值。但是,'shuffle'的返回类型为None,因为该列表将被修改,因此不打印任何内容。解决方法:

# shuffle the list in place 
random.shuffle(b)

# print it
print(b)

如果您更喜欢函数式编程风格,则可能需要创建以下包装函数:

def myshuffle(ls):
    random.shuffle(ls)
    return ls

2
由于这传递了对列表的引用,因此原始文档将被修改。您可能需要在使用deepcopy
shivram.ss 2014年

@ shivram.ss在这种情况下,您想要类似的东西,random.sample(ls, len(ls))如果您真的想沿着那条路线走。
Arda Xi

4

可以定义一个函数shuffledsort与vs 相同sorted

def shuffled(x):
    import random
    y = x[:]
    random.shuffle(y)
    return y

x = shuffled([1, 2, 3, 4])
print x

3
import random

class a:
    foo = "bar"

a1 = a()
a2 = a()
a3 = a()
a4 = a()
b = [a1,a2,a3,a4]

random.shuffle(b)
print(b)

shuffle 到位,因此不要打印结果None,而是列表。


1

您可以这样做:

>>> A = ['r','a','n','d','o','m']
>>> B = [1,2,3,4,5,6]
>>> import random
>>> random.sample(A+B, len(A+B))
[3, 'r', 4, 'n', 6, 5, 'm', 2, 1, 'a', 'o', 'd']

如果要返回到两个列表,则可以将此长列表分成两部分。


1

您可以构建一个将列表作为参数并返回列表的随机版本的函数:

from random import *

def listshuffler(inputlist):
    for i in range(len(inputlist)):
        swap = randint(0,len(inputlist)-1)
        temp = inputlist[swap]
        inputlist[swap] = inputlist[i]
        inputlist[i] = temp
    return inputlist

1
""" to shuffle random, set random= True """

def shuffle(x,random=False):
     shuffled = []
     ma = x
     if random == True:
         rando = [ma[i] for i in np.random.randint(0,len(ma),len(ma))]
         return rando
     if random == False:
          for i in range(len(ma)):
          ave = len(ma)//3
          if i < ave:
             shuffled.append(ma[i+ave])
          else:
             shuffled.append(ma[i-ave])    
     return shuffled

一个小的介绍或解释会有所帮助吗?
kacase

该函数对改组活动很有帮助,想象一下您必须对数字列表进行3次改组,并且在3次中您需要随机进行改组,然后将random参数设为True,否则就不需要随机性并且您想要保留相同的改组顺序,然后不进行任何更改,只需运行代码即可。
Josh Anish

由于没有用例可以让此函数的调用者在运行时决定是否要随机或非随机混洗,因此应将此函数分为两个部分。
toolforger

没有描述非随机混洗应该做什么。(在切线上,这不是答案,所以不是问题,因此它不符合堆栈溢出的目的。)
toolforger

1

您可以使用随机播放或采样。两者均来自随机模块。

import random
def shuffle(arr1):
    n=len(arr1)
    b=random.sample(arr1,n)
    return b

要么

import random
def shuffle(arr1):
    random.shuffle(arr1)
    return arr1

0

确保您没有命名源文件random.py,并且工作目录中没有名为random.pyc ..的文件,这可能会导致程序尝试导入本地random.py文件而不是pythons random模块。


0
def shuffle(_list):
    if not _list == []:
        import random
        list2 = []
        while _list != []:
            card = random.choice(_list)
            _list.remove(card)
            list2.append(card)
        while list2 != []:
            card1 = list2[0]
            list2.remove(card1)
            _list.append(card1)
        return _list

如果您不想使用随机模块,此功能可以为您提供帮助
-Pogramist

该解决方案不仅冗长而且效率低下(运行时间与列表大小的平方成正比)。
toolforger

第二个循环可以替换为_list.extend(list2),它更简洁,更高效。
toolforger

修改参数的Python函数永远不要返回结果。这只是一个约定,但却是一个有用的约定:人们通常没有时间查看他们调用的所有函数的实现,因此任何仅看到您函数名并产生结果的人都会对看到该函数感到惊讶更新其参数。
toolforger

0
import random
class a:
    foo = "bar"

a1 = a()
a2 = a()
b = [a1.foo,a2.foo]
random.shuffle(b)

-1

改组过程是“有替换的”,因此每个项目的出现可能会改变!至少当列表中的项目也同时列出时。

例如,

ml = [[0], [1]] * 10

后,

random.shuffle(ml)

[0]的数目可以是9或8,但不完全是10。


-1

计划:无需依赖库就可以完成改组工作。示例:从元素0的开头开始浏览列表;找到一个新的随机位置,例如6,将0的值放在6中,将6的值放在0中。移到元素1并重复此过程,以此类推。

import random
iteration = random.randint(2, 100)
temp_var = 0
while iteration > 0:

    for i in range(1, len(my_list)): # have to use range with len()
        for j in range(1, len(my_list) - i):
            # Using temp_var as my place holder so I don't lose values
            temp_var = my_list[i]
            my_list[i] = my_list[j]
            my_list[j] = temp_var

        iteration -= 1

您可以像这样在python中交换变量:my_list[i], my_list[j] = my_list[j], my_list[i]
Karolis Ryselis

-2

它工作正常。我在这里尝试使用功能作为列表对象:

    from random import shuffle

    def foo1():
        print "foo1",

    def foo2():
        print "foo2",

    def foo3():
        print "foo3",

    A=[foo1,foo2,foo3]

    for x in A:
        x()

    print "\r"

    shuffle(A)
    for y in A:
        y()

它打印出来:foo1 foo2 foo3 foo2 foo3 foo1(最后一行中的foos具有随机​​顺序)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.