【问题标题】:Index out of range error when creating a random list with no consecutive repetitions创建没有连续重复的随机列表时出现索引超出范围错误
【发布时间】:2019-11-23 15:57:45
【问题描述】:

我正在尝试生成一个包含 100 个元素的列表,这些元素由随机分布的数字 1 到 4 组成,但没有连续重复。我不想确定数字 1 到 4 是否出现相同的次数,我希望它是完全随机的,除了没有连续重复。我写了一些似乎正在这样做的代码,直到它停止并说 list index out of range,但是我无法弄清楚为什么会发生此错误。

from random import randint

guesses = []

for x in range (0, 99):

    guess = randint(1,4)
    guesses.append(guess)

    if x> 0 and guesses[x] == guesses[x-1]:
       guesses.remove(guess)

 print(guesses)

它应该看起来像这样:

123421342312321423124213...23142314213

【问题讨论】:

    标签: python list random


    【解决方案1】:

    您只生成了 99 个元素。 Range(0,99) 从 0 到 98,包括 0 到总共 99 个元素。

    此外,删除重复猜测的代码部分需要将 x 设置回 x - 1。这样,您要创建的每个元素的“计数器”不会比实际拥有的元素数量多 1。

    此外,当您删除此元素时,该方法将删除等于变量guess 的对象的第一个实例,不一定是您刚刚添加的那个。你应该使用 .pop() 查看我截屏的 python 中的示例。

    for x in range (0, 100):
    
        guess = randint(1,4)
        guesses.append(guess)
    
        if x> 0 and guesses[x] == guesses[x-1]:
           guesses.pop()
           x = x - 1
    

    【讨论】:

    • 你应该修正你的缩进。
    【解决方案2】:

    这周我遇到了类似的问题,我的解决方案是每次删除索引时都必须调整计数器(x 它看起来像你),因为数组变短了,所以事情开始发生变化。

    【讨论】:

    • 您应该添加代码以显示更改并对其进行描述。
    • 我只能写 JS,因为我对编程还是很陌生,我不想看起来太笨:) 不过这周刚开始学习 Python。
    【解决方案3】:

    当你从guesses数组中移除一个元素时,它的长度会减少

    使用此代码

    from random import randint
    
    guesses = []
    x = 0
    while x < 100:
    
        guess = randint(1,4)
        guesses.append(guess)
    
        if x > 0 and guesses[x] == guesses[x-1]:
            guesses.pop()
        else:
            x += 1
    
    print(guesses)
    

    【讨论】:

      【解决方案4】:

      您的问题是,即使您删除数字而不是减少数字,数字也会不断增加。我建议改用 while 循环。此外,您应该只在需要时将号码添加到您的列表中,而不是添加它然后删除它。

      from random import randint
      
      guesses = [randint(1,4)]
      x = 1
      
      while x < 100:
      
          guess = randint(1,4)
      
          if guess != guesses[x-1]:
             guesses.append(guess)
             x += 1
      
      print(guesses)
      

      【讨论】:

        【解决方案5】:

        问题是一旦你删除了一个元素,x 就会变得比你的数组大

        所以 guesses[x] 超出范围,因为 x >=guesses.size()

        【讨论】:

          【解决方案6】:

          如果不是删除与之前匹配的元素,而是替换它直到它不删除,您的代码将起作用:

          from random import randint
          
          guesses = [randint(1,4)]
          
          for x in range (1, 100):
          
              guess = randint(1,4)
              guesses.append(guess)
          
              while guesses[x] == guesses[x-1]:
                  guesses[x] = randint(1,4)
          

          两个替代想法:

          您可以创建一组您的选择:

          {1, 2, 3, 4}
          

          然后在每次迭代中从集合中请求random.choice - 最后一项。 choice 需要一些可索引的东西,因此您每次都需要转换为列表,但如果这是一个瓶颈,可能有一些方法可以提高效率:

          from random import choice
          
          choices = {1, 2, 3, 4}
          l = [choice(list(choices))]  # start with one random choice
          
          for i in range(99):
              l.append(choice(list(choices - {l[-1]})))   
          

          这似乎很统一:

          from collections import Counter
          
          counts = Counter(l)
          counts
          
          Counter({3: 26, 2: 25, 1: 26, 4: 23})
          

          使用迭代器
          您可以使用延迟评估的迭代器来完成这一切,然后只需获取所需长度的 islice()

          from random import randint
          from itertools import tee, islice
          
          #generator to makes random ints between start and stop
          def randIt(start, stop):
              while True:
                  yield randint(1,4)
          
          rands, prevs = tee(randIt(1, 4))
          next(prevs)
          
          # non_dupes is a generator that makes non-repeating rands
          non_dupes = (r for r, i in zip(rands, prevs) if r!=i)
          
          # use itertools islice or a loop to get the number you want
          # or just call `next(non_dupes)` for one:
          list(islice(non_dupes, 0, 100))
          

          【讨论】:

            【解决方案7】:

            这是一个使用 numpy 的解决方案

            from time import time
            
            import numpy as np
            
            
            
            def solve_random_non_consecutive(minValue,maxValue,size):
                # initial guess
                a = np.random.randint(minValue,maxValue,size)
                # indexes where a[i] == a[i-1]
                x = np.where(np.diff(a) == 0)[0]
                # as long as we have consecutive duplicates
                while len(x) > 0:
                    # rerandomize all indexes
                    a[x] = np.random.randint(minValue,maxValue,len(x))
                    # find all duplicates
                    x = np.where(np.diff(a) == 0)[0]
                return a
            
            s = time()
            print(solve_random_non_consecutive(1,5,1000000))
            print("Took %0.2fs to solve"%(time()-s)) # took ~ 0.17 seconds to generate 1MIL 
            # any of the solutions using iteration took ~ 10 seconds to generate 1 mil
            

            需要注意的是,由于它会随机重新填充数据,因此每次运行的时间可能会有所不同

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2013-04-07
              • 1970-01-01
              • 2019-09-06
              • 1970-01-01
              • 1970-01-01
              • 2015-06-20
              • 2020-04-26
              • 2015-01-28
              相关资源
              最近更新 更多