简体   繁体   English

在每行之后迭代两个列表切换方向的更多pythonic方式?

[英]More pythonic way to iterate through two lists switching directions after every line?

I am writing some code that loops through two lists in a bit of an odd fashion.我正在编写一些代码,以一种奇怪的方式循环遍历两个列表。 My goal is to iterate through all of list a , using index i , then loop through b using index j and alternate back and forth.我的目标是使用索引i遍历所有列表a ,然后使用索引j遍历b并来回交替。 Ie I want to iterate through pairs in the order:即我想按顺序遍历对:

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

My current code is written like this:我当前的代码是这样写的:

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

However, I would like to be a bit more pythonic, and follow the maxim of但是,我想更加pythonic,并遵循

Flat is better than nested.平面优于嵌套。

What I want to write something that looks more like this:我想写一些看起来更像这样的东西:

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

So my question is: is there a way to accomplish the same goal but be less repetitive, and remove a layer of nesting?所以我的问题是:有没有一种方法可以实现相同的目标但减少重复性,并去除一层嵌套? Broadly, my code is pretty simple but it seems that there's no way to avoid repeating myself in two different ways, am I missing something, or is my implementation in fact the bast way to accomplish this?从广义上讲,我的代码非常简单,但似乎无法避免以两种不同的方式重复自己,我是否遗漏了什么,或者我的实现实际上是实现这一目标的最糟糕的方式?

PS I hope this isn't a duplicate, I couldn't find any other questions addressing this theme. PS我希望这不是重复的,我找不到解决这个主题的任何其他问题。

EDIT FOR CLARITY: My specific requirement is that I process (i, j-1) , (i-1, j) and (i-1, j-1) before hitting (i, j) .编辑清晰:我的具体要求是在点击(i, j)之前处理(i, j-1)(i-1, j)(i-1, j-1) ) 。 Any possible path of iteration satisfying this requirement will work.满足此要求的任何可能的迭代路径都将起作用。 In case you're interested, this is because I am trying to implement a DTW algorithm, where each value assigned in a matrix depends on previous adjacent values.如果您感兴趣,这是因为我正在尝试实现 DTW 算法,其中矩阵中分配的每个值都取决于先前的相邻值。

If you lay out the numbers in an n-row by m-column grid, you can obtain your solution by walking down the first column, then across the first row (starting at column 1), then down the second column (starting at row 1), then across the second row (starting at column 2), then down the third column (starting at row 2), etc. This simply implements that.如果您通过 m 列网格将数字排列在 n 行中,您可以通过沿着第一列走,然后穿过第一行(从第 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)]

Per your "EDIT FOR CLARITY"根据您的“为清晰而编辑”

My specific requirement is that I process (i, j-1), (i-1, j) and (i-1, j-1) before hitting (i, j).我的具体要求是我在点击(i,j)之前处理(i,j-1),(i-1,j)和(i-1,j-1)。

That can just be done by这可以通过

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

If I understand correctly this time, if this was a 5 x 4 (n = 4, m = 3) matrix you basically want the below order:如果这次我理解正确,如果这是一个 5 x 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

You should be able to solve this recursively.你应该能够递归地解决这个问题。

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)

And then:接着:

>>> 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)]

or for your specific use case:或针对您的特定用例:

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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM