2017-08-12 28 views
1

我有以下字典:从字典结合所有可能的选项

d = { 
    'option1': range(0, 5), 
    'optionA': ['a', 'b', 'c'], 
    'extra_option': range(100, 200, 20) 
} 

我在寻找的代码,会为我提供一个数组,像这样:

[ "--option1=0 --optionA=a --extra_option=100", 
    "--option1=0 --optionA=a --extra_option=120", 
    "--option1=0 --optionA=a --extra_option=140", 
    . 
    . 
    . 
    "--option1=5 --optionA=b --extra_option=180"] 

我已经看了在itertools产品和组合中,但两者似乎都不适合这项工作。我想创建这样一个发电机:

def get_options(d, keys): 
    key = keys.pop() 
    for key in d: 
     if len(keys) > 0: 
      for value in d[key]: 
       for other in get_options(d, keys[:]): 
        yield "--%s=%s %s" % (key, value, other) 
     else: 
      for value in d[key]: 
       yield "--%s=%s" % (key, value) 

for x in get_options(d, list(d.keys())): 
     print (x) 

但是,这给我的错误:

$ python3 test.py 
--optionA=a --optionA=a --optionA=a 
--optionA=a --optionA=a --optionA=b 
--optionA=a --optionA=a --optionA=c 
--optionA=a --optionA=a --option1=0 
--optionA=a --optionA=a --option1=1 
--optionA=a --optionA=a --option1=2 
--optionA=a --optionA=a --option1=3 
--optionA=a --optionA=a --option1=4 
--optionA=a --optionA=a --extra_option=100 
--optionA=a --optionA=a --extra_option=120 
--optionA=a --optionA=a --extra_option=140 
--optionA=a --optionA=a --extra_option=160 
--optionA=a --optionA=a --extra_option=180 
Traceback (most recent call last): 
    File "test.py", line 18, in <module> 
    for x in get_options(d, list(d.keys())): 
    File "test.py", line 12, in get_options 
    for other in get_options(d, keys): 
    File "test.py", line 12, in get_options 
    for other in get_options(d, keys): 
    File "test.py", line 8, in get_options 
    key = keys.pop() 
IndexError: pop from empty list 

这不是我所期待的......我在做什么错?任何人都可以告诉我一个更好的方法来做到这一点?提前致谢!

编辑10秒后:

哎呀,所以我还是不得不在那里for key in d从以前的测试...去除(和取消缩进休息了一下),它的工作原理!但我的其他问题仍然存在,有没有更好的方法来做到这一点?

+0

,如果你有工作,但要改善它,考虑http://codereview.stackexchange.com – davedwards

回答

2

事实上,Python提供了类似的功能,称为itertools.productitertools为重复任务打包了许多有用的工具,例如组合,组合,链接等。

product将返回输入迭代的笛卡尔乘积。

这是这样的:

product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy 
product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111 

所以你只需要返回,在每一轮的改变与product。而时间复杂度将是O(n)的!

这是我改进的代码:

from itertools import product 
from collections import OrderedDict 


d = { 
    'option1': range(0, 5), 
    'optionA': ['a', 'b', 'c'], 
    'extra_option': range(100, 200, 20) 
} 


#just make it beautiful 
def ordered(d): 
    temp = OrderedDict() 
    for key, value in d.items(): 
     temp[key] = value 
    return temp 


def merge(d): 
    dKeys = list(ordered(d).keys()) 
    keyStr = "={} --".join(dKeys) 
    keyStr = "--" + keyStr + "={}" 
    dValues = [list(value) for value in d.values()] 
    for value_list in product(*dValues): 
     yield keyStr.format(*value_list) 

for r in merge(d): 
    print(r) 
+0

,代码会更清楚。如果你想了解更多关于'itertools'的信息,我建议你阅读官方文档。 (PS:我认为用你的简单代码格式化'keyStr'是你问题中最难的部分) – WSY