更加 pythonic 的方式来迭代两个列表,每行后切换方向?

问题描述 投票:0回答:1

我正在写一些代码,以一种奇怪的方式循环浏览两个列表。我的目标是遍历所有的 list a,使用指数 i,然后循环到 b 使用指数 j 并来回交替。即我想按顺序迭代对。

(0,0),...,(n,0),(0,1)...(0,m),(1,1)...,(n,1),(1,2)...,(1,m),(2,2),...,(n,m)

我现在的代码是这样写的

while i+j < len(a) + len(b) -2:
    #do stuff
    if direction_toggle:
        if i + 1 > len(a):
            direction_toggle = not direction_toggle
            i = j
        else:
            i += 1
    else:
        if j + 1 > len(b):
            direction_toggle = not direction_toggle
            j = i + 1
        else:
            j += 1

然而,我想更多的pythonic, 并遵循以下的格言:

扁平的比嵌套的好。

我想写的东西更像这样。

while i+j < len(a) + len(b) -2:
    #do stuff
    if direction_toggle:
        var, length = i, len(a)
    else:
        var, length = j, len(b)
    if var + 1 > length:
        direction_toggle = not direction_toggle
    else:
        var += 1

所以我的问题是:有没有一种方法可以达到同样的目的,但又不至于重复,而且还能去掉一层嵌套?大体上,我的代码很简单,但似乎没有办法避免用两种不同的方式来重复,是我遗漏了什么,还是我的实现其实是实现这个目标的混蛋方式?

PS我希望这不是一个重复的问题,我找不到任何其他问题来解决这个主题。

为了清楚起见,我做了编辑。我的具体要求是,我处理 (i, j-1), (i-1, j)(i-1, j-1) 临打 (i, j). 任何可能的迭代路径满足这个要求都可以。如果你感兴趣的话,这是因为我正在尝试实现一个DTW算法,其中矩阵中分配的每个值都取决于之前相邻的值。

python iteration nested-lists
1个回答
1
投票

如果你把数字排列在一个n行m列的网格中,你可以通过沿着第一列走,然后穿过第一行(从第1列开始),然后沿着第二列(从第1行开始),然后穿过第二行(从第2列开始),然后沿着第三列(从第2行开始)等方式获得你的解决方案。这只是简单地实现了这一点。

def gen_tuples(n_rows, n_cols):
    row = col = 0
    while row <= n_rows and col <= n_cols:
        for i in range(row, n_rows + 1):
            yield (i, col)

        for j in range(col + 1, n_cols + 1):
            yield (row, j)

        row += 1
        col += 1


list(gen_tuples(5, 3))

[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0),
 (0, 1), (0, 2), (0, 3),
 (1, 1), (2, 1), (3, 1), (4, 1), (5, 1),
 (1, 2), (1, 3),
 (2, 2), (3, 2), (4, 2), (5, 2),
 (2, 3),
 (3, 3), (4, 3), (5, 3)]

0
投票

根据您的 "为明确而编辑"

我的具体要求是,在打(i,j)之前,我先处理(i,j-1)、(i-1,j)和(i-1,j-1)。

这可以通过以下方式实现

for i in range(n + 1):
    for j in range(m + 1):
         do_stuff()

如果我这次理解正确的话,如果这是一个5×4(n=4,m=3)的矩阵,你基本上想要下面的顺序。

 0 5  6  7
 1 8  12 13
 2 9  14 17
 3 10 15 18
 4 11 16 19

你应该可以用递归方式解决这个问题。

def stripes(r, c, r0=0, c0=0, flip=False):
    for row in range(r0, r + 1):
        yield (row, c0) if not flip else (c0, row)
    if r0 <= r:
        yield from stripes(c, r, r0=c0 + 1, c0=r0, flip=not flip)

然后。

>>> list(stripes(4, 3))
[(0, 0), (1, 0), (2, 0), (3, 0), (4, 0),
 (0, 1), (0, 2), (0, 3),
 (1, 1), (2, 1), (3, 1), (4, 1),
 (1, 2), (1, 3),
 (2, 2), (3, 2), (4, 2),
 (2, 3),
 (3, 3), (4, 3)]

或者针对你的具体使用情况,

cache = {}
for r, c in stripes(R, C):
    inputs = (r - 1, c), (r - 1, c - 1), (r, c - 1)
    a, b, c = (cache.get((x, y)) for x, y in inputs)
    cache[(r, c)] = do_stuff(a, b, c)
© www.soinside.com 2019 - 2024. All rights reserved.