【问题标题】:Create circular iterator from incremental start position从增量起始位置创建循环迭代器
【发布时间】:2018-07-30 07:42:17
【问题描述】:

好的,所以我想在索引中创建一个循环迭代器,如下所示

[0,1,2,3,4,5,6,7,8][1,2,3,4,5,6,7,8,0][2,3,4,5,6,7,8,0,1][3,4,5,6,7,8,0,1,2]...[8,0,1,2,3,4,5,6,7]

其中最大值可能是 8 或其他数字。

到目前为止,我有一些代码不起作用。

a = ['l','m','n','o','p','q','r','s','t'] #len(a) = 9
b = [[]] *len(a)
c = [[]] *len(a)
for offset_index in range(len(a)):
    b[offset_index] = []
    c[offset_index] = []
    for i in range(offset_index, len(a) - offset_index, 1):
        b[offset_index].append(i)
        c[offset_index].append(a[i])
print b

[[0, 1, 2, 3, 4, 5, 6, 7, 8], [1, 2, 3, 4, 5, 6, 7], [2, 3, 4, 5, 6 ], [3, 4, 5], [4], [], [], [], []]

我可以看出这是第二个范围函数的问题,但无法想象一个巧妙的解决方法。

【问题讨论】:

    标签: python python-2.7 loops offset


    【解决方案1】:

    itertools.cycle + itertools.islice

    高效的循环和迭代——在编写此解决方案的过程中没有损坏任何副本。

    from itertools import cycle, islice
    
    l = list(range(9))
    repeats = 8
    
    [list(islice(cycle(l), i, len(l) + i)) for i in range(repeats)]
    
    [[0, 1, 2, 3, 4, 5, 6, 7, 8],
     [1, 2, 3, 4, 5, 6, 7, 8, 0],
     [2, 3, 4, 5, 6, 7, 8, 0, 1],
     [3, 4, 5, 6, 7, 8, 0, 1, 2],
     [4, 5, 6, 7, 8, 0, 1, 2, 3],
     [5, 6, 7, 8, 0, 1, 2, 3, 4],
     [6, 7, 8, 0, 1, 2, 3, 4, 5],
     [7, 8, 0, 1, 2, 3, 4, 5, 6]]
    

    或者,如果您不想保留索引:

    for i in range(repeats):
        idx = list(islice(cycle(l), i, len(l) + i)) 
        ... # do something with idx
    

    列表理解

    追求性能的用户的选择。

    [l[i:] + l[:i] for i in range(repeats)]
    
    [[0, 1, 2, 3, 4, 5, 6, 7, 8],
     [1, 2, 3, 4, 5, 6, 7, 8, 0],
     [2, 3, 4, 5, 6, 7, 8, 0, 1],
     [3, 4, 5, 6, 7, 8, 0, 1, 2],
     [4, 5, 6, 7, 8, 0, 1, 2, 3],
     [5, 6, 7, 8, 0, 1, 2, 3, 4],
     [6, 7, 8, 0, 1, 2, 3, 4, 5],
     [7, 8, 0, 1, 2, 3, 4, 5, 6]]
    

    【讨论】:

    • 如果我需要保留索引以供以后使用,这是最好的答案。谢谢。
    • @Joylove 你的阵列很大吗?在这种情况下,我的选项 1 可能比其他答案更有效。我添加了一个不保留索引的版本。看看吧:)
    【解决方案2】:

    这是我的代码:

    a = [1, 2, 3, 4, 5]
    for slice_index in range(0, len(a)):
        print (a[slice_index::] + a[:slice_index:])
    

    [1、2、3、4、5]
    [2、3、4、5、1]
    [3、4、5、1、2]
    [4、5、1、2、3]
    [5, 1, 2, 3, 4]

    解释: a[slice_index::] 给出数组中 index >= slice_index 的部分。另一个也一样。

    【讨论】:

    • 太棒了。谢谢!
    【解决方案3】:
    a = [0,1,2,3,4,5,6,7,8]
    b = []
    for i in range(len(a)):
        b.append([])
        for j in range(len(a)):
            b[i].append(a[(i+j)%len(a)])
    
    print b
    

    【讨论】:

      【解决方案4】:

      more_itertools.circular_shifts 实现 circular shiftscyclic permutation 的类型。

      代码

      import more_itertools as mit
      
      
      iterable = range(9)
      
      # Option 1
      mit.circular_shifts(iterable)
      

      输出

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

      替代品

      通过相同的third-party library 使用sliding windows

      import itertools as it
      
      
      # Option 2
      list(it.islice(mit.windowed(it.cycle(iterable), n=len(iterable)), len(iterable)))
      
      # Option 3
      list(mit.windowed(mit.ncycles(iterable, n=2), n=len(iterable)))[:-1]
      

      【讨论】:

        【解决方案5】:
        >>> L = ['a', 'b', 'c', 'd', 'e']
        >>> [[L[i-j] for i in range(len(L))] for j in range(len(L), 0, -1)]
        [['a', 'b', 'c', 'd', 'e'],
         ['b', 'c', 'd', 'e', 'a'],
         ['c', 'd', 'e', 'a', 'b'],
         ['d', 'e', 'a', 'b', 'c'],
         ['e', 'a', 'b', 'c', 'd']]
        

        【讨论】:

        • 请在你的回答中添加一些解释。
        • @AndréKool,它类似于 Dawit 的答案,但使用了正负索引的混合而不是模数。将L[i-j] 替换为i-j 以查看生成的索引。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-12-09
        • 2023-03-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-07-13
        相关资源
        最近更新 更多