在每行之后迭代两个列表切换方向的更多 pythonic 方法?
More pythonic way to iterate through two lists switching directions after every line?
我正在编写一些代码,以一种有点奇怪的方式循环遍历两个列表。我的目标是使用索引 i
遍历所有列表 a
,然后使用索引 j
循环遍历 b
并来回交替。 IE。我想按顺序遍历对:
(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,并遵循
的格言
Flat is better than nested.
我想写的东西看起来更像这样:
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)
之前处理 (i, j-1)
、(i-1, j)
和 (i-1, j-1)
。满足此要求的任何可能的迭代路径都将起作用。如果您感兴趣,这是因为我正在尝试实现 DTW 算法,其中矩阵中分配的每个值都取决于之前的相邻值。
根据您的 "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).
这可以通过
完成
for i in range(n + 1):
for j in range(m + 1):
do_stuff()
如果我这次没理解错的话,如果这是一个 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
你应该能够递归地解决这个问题。
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)
如果您将数字排列在 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)]
我正在编写一些代码,以一种有点奇怪的方式循环遍历两个列表。我的目标是使用索引 i
遍历所有列表 a
,然后使用索引 j
循环遍历 b
并来回交替。 IE。我想按顺序遍历对:
(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,并遵循
的格言Flat is better than nested.
我想写的东西看起来更像这样:
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)
之前处理 (i, j-1)
、(i-1, j)
和 (i-1, j-1)
。满足此要求的任何可能的迭代路径都将起作用。如果您感兴趣,这是因为我正在尝试实现 DTW 算法,其中矩阵中分配的每个值都取决于之前的相邻值。
根据您的 "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).
这可以通过
完成for i in range(n + 1):
for j in range(m + 1):
do_stuff()
如果我这次没理解错的话,如果这是一个 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
你应该能够递归地解决这个问题。
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)
如果您将数字排列在 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)]