【问题标题】:Multidimensional Enumeration, how to avoid Code Macro Generation多维枚举,如何避免代码宏生成
【发布时间】:2015-02-21 09:28:13
【问题描述】:

所以我有一个名为 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    

除了问题是我将不得不创建一个自己生成代码的子例程。个人觉得太棒了!但是......也许有一种更“优雅”的方式来做到这一点。相反,应该如何进行?

【问题讨论】:

    标签: python arrays list multidimensional-array nested


    【解决方案1】:

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

    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() 的小修改允许它“访问”实际的嵌套列表对象(我不确定你的问题):

    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'
    

    【讨论】:

      【解决方案2】:

      递归呢?

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

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

      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
      

      【讨论】:

      • String 对象有一个__len__ 方法,但不应递归处理。实际上,只要输入列表中存在字符串,您的代码就会无限递归(直到RuntimeError: maximum recursion depth exceeded)。
      • 是的,我知道,这就是为什么我也建议询问实例的类型,但我们不知道 OP 的多维对象的确切类别 :-)
      • 我们当然知道它们不是字符串。
      猜你喜欢
      • 1970-01-01
      • 2011-01-17
      • 2021-01-04
      • 2011-10-06
      • 1970-01-01
      • 2019-10-29
      • 1970-01-01
      • 1970-01-01
      • 2012-04-26
      相关资源
      最近更新 更多