Python 中优雅地遍历多个 2D 列表

76 阅读3分钟

在 Python 中,当您编写一个基于网格的游戏时,可能会遇到需要遍历多个 2D 列表的情况。例如,您可能需要一个 2D 列表来表示地形,另一个 2D 列表来表示物体。当您需要迭代这些列表并将一个列表中的方格内容影响另一个列表的一部分时,会发现需要编写类似以下的代码:

huake_00183_.jpg

for i in range(len(alist)):
    for j in range(len(alist[i])):
        if alist[i][j].isWhatever:
            blist[i][j].doSomething()

这种写法虽然可以实现目的,但代码冗长且可读性差。有没有一种更简洁、优雅的方式来完成这样的任务呢?

2、解决方案

方法一:使用 itertools.izip() 函数

Python 中的 itertools 模块提供了一个 izip() 函数,可以将多个可迭代对象组合成一个元组列表。我们可以利用这个函数来同时迭代多个 2D 列表。

from itertools import izip

for a_row, b_row in izip(alist, blist):
    for a_item, b_item in izip(a_row, b_row):
        if a_item.isWhatever:
            b_item.doSomething()

这种写法比之前的代码简洁多了,而且可读性也更强。它首先利用 izip() 函数将 alist 和 blist 变成一个元组列表,然后使用两个 for 循环来遍历这个元组列表,从而同时访问 alist 和 blist 中的元素。

方法二:使用生成器表达式

Python 中的生成器表达式是一种非常强大的工具,它可以用来创建生成器对象。生成器对象是一种特殊的可迭代对象,它可以按需生成元素。我们可以利用生成器表达式来同时迭代多个 2D 列表。

for a, b in (pair for (aline, bline) in izip(alist, blist) 
             for pair in izip(aline, bline)):
    if a.isWhatever:
        b.doSomething()

这种写法利用了生成器表达式和 izip() 函数的结合,同时迭代了 alist 和 blist,并将它们的元素组合成一个元组列表。然后,使用 for 循环来遍历这个元组列表,从而同时访问 alist 和 blist 中的元素。

方法三:使用 enumerate() 函数

Python 中的 enumerate() 函数可以将一个可迭代对象中的元素及其索引值组合成一个元组列表。我们可以利用这个函数来同时迭代多个 2D 列表。

for i, arow in enumerate(alist):
    for j, aval in enumerate(arow):
        if aval.isWhatever():
            blist[i][j].doSomething()

这种写法利用了 enumerate() 函数将 alist 中的元素及其索引值组合成一个元组列表,然后使用两个 for 循环来遍历这个元组列表,从而同时访问 alist 和 blist 中的元素。

方法四:将两个 2D 列表合并成一个 3D 列表

如果两个 2D 列表是固定不变的,并且您不想使用上面提到的方法来同时迭代它们,那么您可以考虑将这两个 2D 列表合并成一个 3D 列表。这样,您就可以使用一个 for 循环来遍历这个 3D 列表,从而同时访问 alist 和 blist 中的元素。

alist3d = [[[a_item, b_item] for a_item in a_row] for a_row, b_row in zip(alist, blist)]

for a_row3d in alist3d:
    for a_item3d in a_row3d:
        if a_item3d[0].isWhatever:
            a_item3d[1].doSomething()

这种写法虽然代码量比之前的方法多,但它可以使您的代码更加简洁,而且更容易理解。