【问题标题】:Shuffling a list of objects打乱对象列表
【发布时间】:2010-11-01 21:21:46
【问题描述】:

我有一个对象列表,我想对它们进行随机播放。我以为我可以使用 random.shuffle 方法,但是当列表是对象时,这似乎失败了。有没有洗牌对象的方法或其他解决方法?

import random

class A:
    foo = "bar"

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

print(random.shuffle(b))

这将失败。

【问题讨论】:

  • 你能举例说明它是如何失败的吗? random.shuffle 应该不受列表中对象类型的影响。
  • >>> a1 = a() >>> a2 = a() >>> b = [a1,a2] >>> b [<__main__.a instance at>, <__main__ .a instance at>] >>> print random.shuffle(b) None
  • 如下所述,random.shuffle 不会返回新的打乱列表;它会随机播放列表。所以你不应该说“print random.shuffle(b)”,而应该在一行上做 shuffle,在下一行打印 b。
  • 如果您尝试对 numpy 数组进行洗牌,请参阅下面的答案。
  • 是否有一个选项不会改变原始数组但返回一个新的洗牌数组?

标签: python list random shuffle


【解决方案1】:

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

请注意,随机播放在原地工作,并返回无。

【讨论】:

  • @seokhoonlee 两者都不是。它是一个伪随机数生成器,在可能的情况下,它由操作系统的真实随机源播种。除了密码学目的之外,它是随机的“足够”。这在random module's documentation中有详细说明。
  • 对新列表使用克隆
  • 是否有一个选项不会改变原始数组但返回一个新的洗牌数组?
  • @CharlieParker:我不知道。你可以使用random.sample(x, len(x)) 或者只是复制一份shuffle。对于有类似问题的list.sort,现在有list.sorted,但shuffle 没有类似的变体。
  • @seokhonlee 用于加密安全随机性,请改用from random import SystemRandom;添加cryptorand = SystemRandom()并将第3行更改为cryptorand.shuffle(x)
【解决方案2】:

正如您所了解的,问题是就地改组。我也经常遇到问题,而且似乎也经常忘记如何复制列表。使用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)(用换行符替换;)
  • old[:] 也可以对列表old 进行浅拷贝。
  • sample() 对于数据分析的原型设计特别有用。 sample(data, 2) 用于设置管道的胶水代码,然后逐步“扩大”它,直到 len(data)
【解决方案3】:

我也花了一些时间才明白这一点。但是 shuffle 的文档很清楚:

随机播放列表 x 就位;返回无。

所以你不应该print(random.shuffle(b))。而是先使用random.shuffle(b),然后再使用print(b)

【讨论】:

    【解决方案4】:
    #!/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]
    

    【讨论】:

      【解决方案5】:

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

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

      https://numpy.org/doc/stable/reference/random/generated/numpy.random.shuffle.html

      【讨论】:

      • 我喜欢这个答案的地方是我可以在 numpy.我敢打赌,在随机模块中有一种方法可以做到这一点,但这对我来说现在并不明显......这意味着我需要阅读更多内容。
      【解决方案6】:
      >>> import random
      >>> a = ['hi','world','cat','dog']
      >>> random.shuffle(a,random.random)
      >>> a
      ['hi', 'cat', 'dog', 'world']
      

      它对我来说很好用。确保设置随机方法。

      【讨论】:

      • 仍然对我不起作用,请参阅已编辑问题中的示例代码。
      • 第二个参数默认为random.random。把它放在外面是绝对安全的。
      • @alvas random.shuffle(a) 不返回任何东西,即它返回 None 。所以你必须检查一个不返回值。
      【解决方案7】:

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

      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 / Scipy

      ​​>

      如果你的列表是 numpy 数组,那就更简单了:

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

      微处理器

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

      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 接受任意数量的参数。因此,您还可以使用它随机播放三个或更多列表。

      【讨论】:

      • 我使用了替代方法“from sklearn.utils import shuffle”、“list1,list2=shuffle(list1,list2)”,但 list1 和 list2 随机交换,这是我不想要的。
      【解决方案8】:

      对于单行,使用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]

      【讨论】:

        【解决方案9】:
        from random import random
        my_list = range(10)
        shuffled_list = sorted(my_list, key=lambda x: random())
        

        此替代方案可能对您想要交换排序功能的某些应用程序有用。

        【讨论】:

        • 另外,请注意,感谢sorted,这是一个功能性随机播放(如果您喜欢这种事情)。
        • 由于 Timsort 的稳定性,这并不是真正随机分布值。 (具有相同键的值按其原始顺序保留。)编辑:我想这并不重要,因为与 64 位浮点数发生冲突的风险非常小。
        【解决方案10】:

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

        另一种方法是使用numpy.random.shuffle。如果您已经在使用 numpy,那么这是通用 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]])
        

        【讨论】:

        • 另外,numpy.random.permutation 可能感兴趣:stackoverflow.com/questions/15474159/shuffle-vs-permute-numpy
        • 你有使用random.shuffle时在数组中创建重复数据的例子吗?
        • 是的 - 它包含在我的答案中。请参阅标题为“示例”的部分。 ;)
        • 没关系,我看到三个元素并认为它是相同的。不错的发现
        • random.shuffle 文档应该大喊不要与 numpy 数组一起使用
        【解决方案11】:

        'print func(foo)' 将在使用 'foo' 调用时打印 'func' 的返回值。 然而,'shuffle' 的返回类型为 None,因为列表将被修改到位,因此它什么也不打印。 解决方法:

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

        如果您更喜欢函数式编程风格,您可能想要制作以下包装函数:

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

        【讨论】:

        • 因为这传递了对列表的引用,所以原始的被修改了。您可能希望在使用 deepcopy 改组之前复制列表
        • @shivram.ss 在这种情况下,如果你真的想走这条路,你会想要random.sample(ls, len(ls)) 这样的东西。
        【解决方案12】:

        可以定义一个名为 shuffled 的函数(与 sortsorted 的含义相同)

        def shuffled(x):
            import random
            y = x[:]
            random.shuffle(y)
            return y
        
        x = shuffled([1, 2, 3, 4])
        print x
        

        【讨论】:

          【解决方案13】:
          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,而是列表。

          【讨论】:

            【解决方案14】:

            你可以这样做:

            >>> 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']
            

            如果您想返回两个列表,则将这个长列表分成两个。

            【讨论】:

              【解决方案15】:

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

              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
              

              【讨论】:

                【解决方案16】:
                """ 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
                

                【讨论】:

                • 一个小小的介绍或解释会有帮助吗?
                • 该函数有助于洗牌活动,假设您必须将数字列表洗牌三次,并且在这三次您需要随机洗牌,然后只需将随机参数设置为 True 否则,如果您不需要随机性,并且您希望保留相同的洗牌顺序,然后不要进行任何更改,只需运行代码即可。
                • 由于没有用例让这个函数的调用者在运行时决定他是想要随机还是非随机洗牌,所以这个函数应该分成两个。
                • 没有描述非随机洗牌应该做什么。 (在切线上,它不是问题的答案,所以它不符合 Stack Overflow 的目的。)
                【解决方案17】:

                您可以使用 shuffle 或 sample 。两者都来自随机模块。

                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
                

                【讨论】:

                  【解决方案18】:

                  如果您需要就地洗牌和操纵种子的能力,这个sn-p会有所帮助:

                  from random import randint
                  
                  a = ['hi','world','cat','dog']
                  print(sorted(a, key=lambda _: randint(0, 1)))
                  

                  请记住,“洗牌”是按随机键排序。

                  【讨论】:

                    【解决方案19】:

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

                    【讨论】:

                      【解决方案20】:
                      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
                      

                      【讨论】:

                      • 如果你不想使用随机模块,这个功能可以帮助你
                      • 这种解决方案不仅冗长而且效率低下(运行时间与列表大小的平方成正比)。
                      • 第二个循环可以用_list.extend(list2)代替,更简洁高效。
                      • 修改参数的 Python 函数永远不应该返回结果。这只是一种约定,但很有用:人们通常没有时间查看他们调用的所有函数的实现,因此任何人只要看到您的函数名称并知道它有结果,就会对看到该函数感到非常惊讶更新其参数。
                      【解决方案21】:
                      import random
                      class a:
                          foo = "bar"
                      
                      a1 = a()
                      a2 = a()
                      b = [a1.foo,a2.foo]
                      random.shuffle(b)
                      

                      【讨论】:

                        【解决方案22】:

                        洗牌过程是“有替换”,所以每个项目的出现可能会发生变化!至少当列表中的项目也是列表时。

                        例如,

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

                        之后,

                        random.shuffle(ml)
                        

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

                        【讨论】:

                          【解决方案23】:

                          计划:写出洗牌而不依赖图书馆来做繁重的工作。示例:从元素 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]
                          【解决方案24】:

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

                              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()
                          

                          打印出来: 富1 富2 富3 富2 富3 富1 (最后一行的foos有一个随机的顺序)

                          【讨论】:

                            猜你喜欢
                            • 2012-04-03
                            • 2021-03-09
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 1970-01-01
                            • 2018-05-24
                            • 2019-04-26
                            • 2013-07-12
                            相关资源
                            最近更新 更多