多维枚举,如何避免代码宏生成

Multidimensional Enumeration, how to avoid Code Macro Generation

所以我有一个名为 Object 的多维列表,有 n 个维度

我正在为这个对象的所有元素执行一个过程(可以是任何东西,包括其他多维列表)

所以我开始生成以下枚举对象的归纳方式

案例 1:1-d(列表)

i = 0
while(i < len(Object)):
    f(Object[i])
    i+=1

案例 2:2-d(列表中的列表)

i = 0
while(i < len(Object)):
    j = 0 
    while(j < len(Object[i][j])):
         f(Object[i])
         j+=1
    i+=1

至此直观明显,可以通过以下代码遍历n维对象

indexarray = [] #multi dimensional index structure
i = 0
while(i < n):
     indexarray.append(0)
     i+=1
#Prepared the indices

while(indexarray[0] < len(Object)):
    indexarray[1] = 0
    while(indexarray[1] < len(Object[indexarray[0]])):
        indexarray[2] = 0
        while(indexarray[2] < len(Object[indexarray[0]][indexarray[1]])):
            indexarray[3] = 0
                .
                    .
                        .
                         indexarray[n-1] = 0
                         while(indexarray[n-1] < len(Object[indexarray[0]][...]))
                             f(Object[...])
                             indexarray[n-1]+=1
                         .
                     .
                 .
             indexarray[2]+=1
         indexarray[1]+=1
     indexarray[0]+=1    

唯一的问题是我将不得不创建一个自己生成代码的子例程。我个人认为那太棒了!但是...也许还有更多 "elegant" 方法可以做到这一点。应该如何进行呢?

递归怎么样?

def traverse_object_dfs(myobject):
    for irun in range(len(myobject)):
        traverse_object_dfs(myobject[irun])

    f(myobject)

但问题是,您的函数 f 应用于每个深度。所以你需要找出你是否处于第二低的递归级别。您的对象是否支持 ndim 之类的东西,即您事先知道维度?否则我们可以尝试询问最内层元素是否支持 __len__ 操作(或者询问它是否是您的多维数组对象的实例,如果您的最内层元素也支持 __len__ 则您应该这样做为了避免无限递归,感谢您在评论中再次指出这一点!):

def f(myobject):
    print myobject

def traverse_object_dfs(myobject):
    for irun in range(len(myobject)):
        if hasattr(myobject[irun], '__len__'): ## or isinstance(myobject[irun], YourClass) # if innermost elements also support '__len__':
            traverse_object_dfs(myobject[irun])
        else:
            f(myobject[irun])

x = [[[1,2],[3,4]],[[5,6],[7,8]]]
traverse_object_dfs(x)

打印

1
2
3
4
5
6
7
8

您可以使用递归遍历列表的嵌套元素,即本身是列表(或可能是元组)的元素。此函数将遍历给定列表的所有元素,根据需要下降到嵌套列表和元组:

def visit_item(item):
    print 'visit_item(): called on %r' % item

def traverse_list(l):
    for item in l:
        if isinstance(item, (list, tuple)):
            traverse_list(item)
        else:
            visit_item(item) 

visit_item() 与列表的每个项目一起调用,嵌套列表除外。这是一个例子 运行:

>>> l = [[1, 2, 3, 4], 'hello', 444, ['a', 'b', [7, 7, [3, 2, 1], 7, 7, 7], 'c']]
>>> traverse_list(l)
visit_item(): called on 1
visit_item(): called on 2
visit_item(): called on 3
visit_item(): called on 4
visit_item(): called on 'hello'
visit_item(): called on 444
visit_item(): called on 'a'
visit_item(): called on 'b'
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on 3
visit_item(): called on 2
visit_item(): called on 1
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on 'c'

traverse_list() 的一个小修改允许它 "visit" 实际的嵌套列表对象,如果需要的话(我不确定你的问题):

def traverse_list(l):
    for item in l:
        visit_item(item)
        if isinstance(item, (list, tuple)):
            traverse_list(item)

>>> traverse_list(l)
visit_item(): called on [1, 2, 3, 4]
visit_item(): called on 1
visit_item(): called on 2
visit_item(): called on 3
visit_item(): called on 4
visit_item(): called on 'hello'
visit_item(): called on 444
visit_item(): called on ['a', 'b', [7, 7, [3, 2, 1], 7, 7, 7], 'c']
visit_item(): called on 'a'
visit_item(): called on 'b'
visit_item(): called on [7, 7, [3, 2, 1], 7, 7, 7]
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on [3, 2, 1]
visit_item(): called on 3
visit_item(): called on 2
visit_item(): called on 1
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on 7
visit_item(): called on 'c'