【问题标题】:Python -- how to loop over range starting at random pointPython - 如何从随机点开始循环范围
【发布时间】:2012-04-01 06:02:03
【问题描述】:

我有一个类别列表 (1-4),我想要一个循环来遍历所有类别。但是,如果我的起点在 list[0] 之前,我需要能够从一个随机类别开始并绕到列表的开头。

我能够以一种相当冗长的方式做到这一点,但我想知道是否有更快/更优雅的方式。这是我所做的(并且有效):

def categorize(self, cat):

    cats = [1,2,3,4]
    if cat > 1: 
        ncats = cats[:(cat-1)]
        cats = cats[(cat-1):]
        cats.extend(ncats)

    for c in cats:
        pass

【问题讨论】:

    标签: python list loops


    【解决方案1】:

    总体思路是:

    >>> cats = [1, 2, 3, 4]
    >>> import random
    >>> r = random.randrange(len(cats))
    >>> for i in range(len(cats)):
    ...     current = cats[(r+i)%len(cats)]
    ...     print current
    ...
    3
    4
    1
    2
    

    【讨论】:

      【解决方案2】:
      from random import randrange
      cats = [1,2,3,4]
      i = randrange(len(cats))
      
      for c in cats[i:]+cats[:i]:
         pass
      

      (根据建议将choice 更改为randrange

      【讨论】:

      • +1,但randrange(len(cats)) 会比使用choice(range(len(cats))) 更优雅
      • 模数解决方案不是更高效吗? (他们不需要创建新列表——如果猫很大怎么办。)
      • “我有一个类别列表 (1-4)”。我会选择你认为最易读的任何版本。
      • 我一开始并没有说清楚起始索引必须由另一个函数提供。但我喜欢你对循环语法的浓缩。在调用函数中,我实际上使用 randrange() 来生成循环的起始索引。
      【解决方案3】:
      from random import shuffle
      shuffle(cats)
      for c in cats:
          loop expressions here
      

      【讨论】:

      • 这会破坏排序,不是吗?
      • 对不起,我在最初的问题中不清楚。列表必须保持有序,并且起点(尽管是任意的)由另一个函数提供。
      【解决方案4】:

      嗯,你可以把它减少到cats = cats[cat - 1:] + cats[:cat - 1]

      或者构建一个覆盖 iter 的自定义数据结构,以便它从任意点循环一次且仅一次循环您的列表。

      【讨论】:

      • 对,我忘了我可以使用 + 而不是 .extend()
      【解决方案5】:
      >>> cats = [1,2,3,4]
      >>> import random
      >>> random.shuffle(cats)
      >>> cats
      [1, 3, 4, 2]
      >>> random.shuffle(cats)
      >>> cats
      [1, 4, 3, 2]
      

      [更新]

      >>> def circle_iter(items, start=0):
      ...     l = len(items)
      ...     for i in items:
      ...         yield items[start]
      ...         start += 1
      ...         if start == l: start = 0
      ...
      >>> cats = [ 1, 2, 3, 4 ]
      >>> for cat in circle_iter(cats, 2): print cat
      ...
      3
      4
      1
      2
      >>> for cat in circle_iter(cats, 1): print cat
      ...
      2
      3
      4
      1
      

      【讨论】:

      • 对不起,我在最初的问题中不清楚。是的,列表必须保持有序,并且起点(尽管是任意的)由另一个函数提供。
      【解决方案6】:

      使用模运算符!

      import random
      
      cats = [1,2,3,4]
      
      i = random.randint(0,3)
      
      for n in range(len(cats)):
          print cats[i%len(cats)]
          i+=1
      

      【讨论】:

        【解决方案7】:

        原始列表是否需要保持有序?因为否则您可以使用 random.shuffle 将其随机化:

        cats = [1,2,3,4]
        import random
        random.shuffle(cats)
        # Cats will now be in random order and can be looped normally.
        

        【讨论】:

        • 对不起,我在最初的问题中不清楚。是的,列表必须保持有序,并且起点(尽管是任意的)由另一个函数提供。
        【解决方案8】:

        应该这样做:

        import random
        cats = [1,2,3,4]
        start = random.choice(cats)
        new_order_cats = cats[cats.index(start):] + cats[:cats.index(start)]
        print 'new order', new_order_cats
        

        【讨论】:

          【解决方案9】:

          对于通用的 warp/round-robin 解决方案,我建议如下:

          from itertools import cycle:
          from random import choice
          
          cats = [1,2,3,4]
          def warp(iterable, start):
              c = cycle(iterable)
              while c.next() is not start: pass
              for counter in range(len(iterable)):
                  yield c.next()
          
          #random start part:
          for cat in warp(cats, choice(cats)):
              print cat
          

          iterable-items 的类型无关紧要,您不必检查索引号,只需使用项目本身!

          【讨论】:

          • 也许你的意思是'wrap'而不是'warp'?
          • 不 - 我的意思是扭曲以避免与 functools.wrap 混淆
          【解决方案10】:
          import random
          cats = [1,2,3,4]
          
          def cycle_cats(items, start):
              sorted_items = items[items[start]:] + items[:items[start]]
              for item in sorted_items:
                  yield item
          
          for cat in cycle_cats(cats, random.choice(cats)):
              print cat
          

          保留顺序,不关心猫列表的长度,并期望调用者指定入口点。

          【讨论】:

          • @PauloScardine - 同意。我已经相应地编辑了我的答案。干杯!
          猜你喜欢
          • 2019-08-27
          • 2021-12-18
          • 2015-12-16
          • 1970-01-01
          • 2011-08-25
          • 1970-01-01
          • 2014-05-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多