对于每个循环具有未定义的内部循环数

时间:2014-12-11 02:58:00

标签: python-2.7 iteration

假设foo是一个列表或其他迭代器。我想要一些东西,以便我可以(伪代码):

for i in foo
    for j in foo - [i]
        for k in foo - [i, j]
            ...
                for some_var in foo - [i, j, k, ...]//only one value left in foo
                    do_something(some_args)

有没有办法在python中执行此操作?我是否可以在循环中执行此操作,是否必须使用递归,或者我是否必须(仅在没有其他方式)编写代码对象?

1 个答案:

答案 0 :(得分:1)

你的问题与组合学有关。特别是笛卡尔产品。

如果没有递归,您需要知道要运行多少个循环嵌套。但是,您不需要提前了解此信息。只要你能动态地获得它就可以了。

请考虑从我的其中一个回购中获取此代码:https://github.com/Erotemic/utool/blob/next/utool/util_dict.py

from itertools import product 
import six

varied_dict = {
'logdist_weight': [0.0, 1.0],
'pipeline_root': ['vsmany'], 
'sv_on': [True, False, None]
}

def all_dict_combinations(varied_dict):
       tups_list = [[(key, val) for val in val_list]
             for (key, val_list) in six.iteritems(varied_dict)]
       dict_list = [dict(tups) for tups in product(*tups_list)]
       return dict_list

dict_list = all_dict_combinations(varied_dict)

运行此代码将导致dict_list为

    [
        {'pipeline_root': 'vsmany', 'sv_on': True, 'logdist_weight': 0.0},
        {'pipeline_root': 'vsmany', 'sv_on': True, 'logdist_weight': 1.0},
        {'pipeline_root': 'vsmany', 'sv_on': False, 'logdist_weight': 0.0},
        {'pipeline_root': 'vsmany', 'sv_on': False, 'logdist_weight': 1.0},
        {'pipeline_root': 'vsmany', 'sv_on': None, 'logdist_weight': 0.0},
        {'pipeline_root': 'vsmany', 'sv_on': None, 'logdist_weight': 1.0},
    ]

然后你可以编写像

这样的代码
  for some_vars in dict_list:
      do_something(some_vars)

如果你要列出foo可以在我称之为vary_dict的每个嵌套级别中列出的每个值,那么你可以找到你的问题的解决方案。另请注意,vary_dict可以动态构建,并且它实际上不必是dict。如果您修改了我的代码,您可以使用其他结构列表轻松指定值。

上面代码中的神奇之处在于使用了itertools.product函数。我建议你看一下。 https://docs.python.org/2/library/itertools.html#itertools.product