【问题标题】:Randomly selecting a different pair of items from a list从列表中随机选择一对不同的项目
【发布时间】:2017-12-23 09:26:58
【问题描述】:

代码:

import random

x = ['A','B','C','D','E','F',
     'G','H','I','J','K','L',
     'M','N','O','P','Q','R',
     'S','T','U','V','W','X',
     'Y','Z']

y1 = random.sample(x, 2)
y2 = random.sample(x, 2)
y3 = random.sample(x, 2)
y4 = random.sample(x, 2)
y5 = random.sample(x, 2)

查询

如上图,我选择了5个随机样本组合,并在变量y'x'下声明它们。

为了改进我的代码,我想这样做,但要确保列表中的一个项目在所有变量输出中不出现多次,其中所有组合都是不同的且不重复。我希望实现这一点,而不必从列表中删除项目,因为它稍后在代码中被重用。

预期输出(示例):

>>> y1
['A', 'Q']
>>> y2
['E', 'K']
>>> y3
['C', 'O']
>>> y4
['Z', 'X']
>>> y5
['P', 'L']

【问题讨论】:

    标签: python python-2.7 list random


    【解决方案1】:

    您可以遍历生成的样本并从x 中删除元素:

    x = ['A','B','C','D','E','F',
     'G','H','I','J','K','L',
     'M','N','O','P','Q','R',
     'S','T','U','V','W','X',
     'Y','Z']
    
    new_x = x[:]
    
    import random
    final_list = []
    for i in range(5):
       the_sample = random.sample(new_x, 2)
       final_list.append(the_sample)
       for b in the_sample:
           new_x.remove(b)
    

    输出:

    [['C', 'R'], ['L', 'V'], ['W', 'Y'], ['D', 'O'], ['J', 'Q']]
    

    【讨论】:

    • 谢谢!虽然,“我希望实现这一点,而不必从列表中删除项目,因为它稍后会在代码中重用。”
    【解决方案2】:

    您可以随机播放列表的副本(您说您想重复使用它,因此需要制作副本,因为随机播放可以在原地工作),然后为每个样本取 2 个元素:

    import random
    
    x_copy = x[:]  # copy
    random.shuffle(x_copy)
    y1 = x[:2]
    y2 = x[2:4]
    y3 = x[4:6]
    y4 = x[6:8]
    y5 = x[8:10]
    

    或者如果您不想硬编码yis:

    x_copy = x[:]  # copy
    random.shuffle(x_copy)
    y = [x_copy[i*2: (i+1)*2] for i in range(5)]
    print(y)
    # [['W', 'Z'], ['A', 'Q'], ['B', 'J'], ['O', 'D'], ['X', 'E']]
    

    【讨论】:

    • 太完美了!谢谢。我不特别关注这部分:[i*2: (i+1)*2]。介意澄清吗? ;)
    • 您是指列表理解还是x_copy[i*2: (i+1)*2] 部分?
    • 是的,一点点 ;/ - 你提到的“部分” ;)
    • 列表推导只是for-loop 的替代方案。循环变量i 取值 0-5(5 是唯一的)。在第一次迭代中i=0,因此它附加了x_copy[0: 2],因为2*i = 0(i+1)*2 = 2。在第二次迭代中 i=1 和切片是 x_copy[2: 4] 等等。这只是我对切片进行硬编码的第一个变体的自动化版本。 :)
    【解决方案3】:

    您可以使用numpy.random.choice。其目的是从类似数组的对象(也适用于您的列表)中选择使用 (replace=True) 或不使用 (replace=False) 替换:

    import numpy as np
    x = ['A','B','C','D','E','F',
         'G','H','I','J','K','L',
         'M','N','O','P','Q','R',
         'S','T','U','V','W','X',
         'Y','Z']
    np.random.choice(x, size=(5, 2), replace=False)
    

    结果:

    array([['Y', 'Q'],
           ['W', 'R'],
           ['O', 'H'],
           ['Z', 'G'],
           ['L', 'M']], 
          dtype='<U1')
    

    这将返回一个包含 5 行的数组,每行包含一个大小为 2 的样本。

    【讨论】:

      【解决方案4】:

      您可以简单地为生成的值构建一个“缓存” - 所以x 的元素不会被删除:

      import random
      
      class SampleCache():
          x = ['A','B','C','D','E','F',
               'G','H','I','J','K','L',
               'M','N','O','P','Q','R',
               'S','T','U','V','W','X',
               'Y','Z']
      
          def __init__(self):
              self.cache = []
      
          def get(self):
              _iterations = 0
              while 1:
                  sample = random.sample(self.x, 2)
                  if not sample in self.cache:
                      self.cache.append(sample)
                      return sample
      
                  if _iterations > 1000: # just to prevent NOT to run into an infinite loop
                      break
      
      
      s = SampleCache()
      for x in range(25):
          print(s.get())
      

      【讨论】:

        【解决方案5】:

        使用random.sample 生成初始列表的混洗副本,并使用生成器根据需要生成混洗后的值。

        def random_sample(x, n):
            shuffled = random.sample(x, k=len(x))
            for val in range(0, len(x), n):
                yield shuffled[val: val+n]
        
        print([sample for sample in random_sample(x, 2)])
        

        输出;

        [['I', 'O'], ['V', 'T'], ['U', 'J'], ['L', 'A'], 
         ['E', 'G'], ['Q', 'F'], ['M', 'H'], ['B', 'K'], 
         ['R', 'P'], ['W', 'N'], ['D', 'S'], ['Z', 'Y'], 
         ['X', 'C']]
        

        如果您想要恰好五个随机值,请使用它;

        samples = random_sample(x,  2)
        five_samples = [next(samples) for _ in range(5)]
        print(five_samples)
        

        如果想要一次一个,然后使用,

        samples = random_sample(x,  2)
        print(next(samples))
        ...
        print(next(samples))
        

        【讨论】:

          【解决方案6】:

          random.sample 是正确的方法,你只需要调用一次 10 个字母而不是 5 次 2 个字母:

          import random
          import string
          
          
          def random_letters(m=5, n=2):
              letters = random.sample(string.ascii_uppercase, m * n)
              return [letters[n * i:n * (i + 1)] for i in range(m)]
          
          print(random_letters())
          # [['I', 'X'], ['J', 'U'], ['O', 'W'], ['G', 'C'], ['D', 'F']]
          print(random_letters())
          # [['J', 'X'], ['N', 'P'], ['A', 'C'], ['O', 'Z'], ['B', 'H']]
          print(random_letters())
          # [['U', 'T'], ['J', 'N'], ['C', 'H'], ['D', 'I'], ['K', 'P']]
          print(random_letters())
          # [['U', 'G'], ['L', 'V'], ['A', 'R'], ['J', 'F'], ['S', 'C']]
          print(random_letters())
          # [['Y', 'C'], ['R', 'B'], ['E', 'I'], ['S', 'T'], ['H', 'X']]
          

          【讨论】:

            猜你喜欢
            • 2012-09-11
            • 1970-01-01
            • 2017-11-10
            • 2021-11-17
            • 2011-02-28
            • 2010-09-23
            • 2011-11-14
            • 1970-01-01
            相关资源
            最近更新 更多