如何在Python中计算N个不同字典的所有组合

发布于 2025-01-11 10:07:36 字数 2785 浏览 0 评论 0原文

挑战

我需要将各种字典组合在一起以获得所有可能的组合,同时还需要一种可以采用 (N) 个字典的方法。我有以下适用于单个案例的代码,但我正在寻找更优雅和可扩展的解决方案。

当前解决方案

这适用于指定数量的字典(profile、env、test_vars):

profile = {
    "normal": {"profile": "normal"},
    "special": {"profile": "special"}
}

environment = {
    "legacy": {"id": 123},
    "staging": {"id": 123, "sid": 123123},
    "production": {"pid": 14941729}
}

test_vars = {
    "no_tests": {"var1": ""},
    "var1:prod": {"var1": "prod"},
    "var1+var2": {"var1": "alpha", "var2": "alpha"},
    "var2_beta": {"var2": "beta"},
    "var2_alpha": {"var2": "alpha"}
}

total = [
    {"{}|{}|{}".format(pk, ek, tk): {**pv, **ev, **tv}}
    for pk, pv in profile.items()
    for ek, ev in environment.items()
    for tk, tv in test_vars.items()
]

result = [{id: '&'.join(["{}={}".format(i, x) for i, x in v.items()])
  for id, v in condition.items()}
 for condition in total]

result

结果

输出如下所示,其中列表的每个元素指定一个“测试”标识符”和表示为查询字符串参数的“测试变量”。

Out[68]: 
[{'normal|legacy|no_tests': 'profile=normal&id=123&var1='},
 {'normal|legacy|var1:prod': 'profile=normal&id=123&var1=prod'},
 {'normal|legacy|var1+var2': 'profile=normal&id=123&var1=alpha&var2=alpha'},
 {'normal|legacy|var2_beta': 'profile=normal&id=123&var2=beta'},
 {'normal|legacy|var2_alpha': 'profile=normal&id=123&var2=alpha'},
 {'normal|staging|no_tests': 'profile=normal&id=123&sid=123123&var1='},
 {'normal|staging|var1:prod': 'profile=normal&id=123&sid=123123&var1=prod'},
 {'normal|staging|var1+var2': 'profile=normal&id=123&sid=123123&var1=alpha&var2=alpha'},
 {'normal|staging|var2_beta': 'profile=normal&id=123&sid=123123&var2=beta'},
 {'normal|staging|var2_alpha': 'profile=normal&id=123&sid=123123&var2=alpha'},
 {'normal|production|no_tests': 'profile=normal&pid=14941729&var1='},
 {'normal|production|var1:prod': 'profile=normal&pid=14941729&var1=prod'},
 {'normal|production|var1+var2': 'profile=normal&pid=14941729&var1=alpha&var2=alpha'},
 {'normal|production|var2_beta': 'profile=normal&pid=14941729&var2=beta'},
 {'normal|production|var2_alpha': 'profile=normal&pid=14941729&var2=alpha'},...

我的问题

这无法扩展到添加更多配置字典。

假设我现在想添加另一个配置字典,例如 release。我必须添加新的字典,并修改“总”理解,如下所示:

total = [
    {"{}|{}|{}|{}".format(pk, ek, tk, rk): {**pv, **ev, **tv, **rv}}
    for pk, pv in profile.items()
    for ek, ev in environment.items()
    for tk, tv in test_vars.items()
    for rk, rv in release_vars.items()
]

这看起来不优雅,尤其是当我可以处理 00 的配置字典时。

任何人都可以帮助设计一些更具可扩展性的东西吗?

The Challenge

I need to combine various dictionaries together to obtain all possible combinations, whilst also having an approach that can take (N) number of dictionaries. I have the following code which works for a single case, but I'm seeking a more elegant and scalable solution.

Current Solution

This works for a specified number of dictionaries (profile, env, test_vars):

profile = {
    "normal": {"profile": "normal"},
    "special": {"profile": "special"}
}

environment = {
    "legacy": {"id": 123},
    "staging": {"id": 123, "sid": 123123},
    "production": {"pid": 14941729}
}

test_vars = {
    "no_tests": {"var1": ""},
    "var1:prod": {"var1": "prod"},
    "var1+var2": {"var1": "alpha", "var2": "alpha"},
    "var2_beta": {"var2": "beta"},
    "var2_alpha": {"var2": "alpha"}
}

total = [
    {"{}|{}|{}".format(pk, ek, tk): {**pv, **ev, **tv}}
    for pk, pv in profile.items()
    for ek, ev in environment.items()
    for tk, tv in test_vars.items()
]

result = [{id: '&'.join(["{}={}".format(i, x) for i, x in v.items()])
  for id, v in condition.items()}
 for condition in total]

result

Result:

The output looks like this, where each element of the list specifies a "test identifier" and the "test variables" expressed as querystring parameters.

Out[68]: 
[{'normal|legacy|no_tests': 'profile=normal&id=123&var1='},
 {'normal|legacy|var1:prod': 'profile=normal&id=123&var1=prod'},
 {'normal|legacy|var1+var2': 'profile=normal&id=123&var1=alpha&var2=alpha'},
 {'normal|legacy|var2_beta': 'profile=normal&id=123&var2=beta'},
 {'normal|legacy|var2_alpha': 'profile=normal&id=123&var2=alpha'},
 {'normal|staging|no_tests': 'profile=normal&id=123&sid=123123&var1='},
 {'normal|staging|var1:prod': 'profile=normal&id=123&sid=123123&var1=prod'},
 {'normal|staging|var1+var2': 'profile=normal&id=123&sid=123123&var1=alpha&var2=alpha'},
 {'normal|staging|var2_beta': 'profile=normal&id=123&sid=123123&var2=beta'},
 {'normal|staging|var2_alpha': 'profile=normal&id=123&sid=123123&var2=alpha'},
 {'normal|production|no_tests': 'profile=normal&pid=14941729&var1='},
 {'normal|production|var1:prod': 'profile=normal&pid=14941729&var1=prod'},
 {'normal|production|var1+var2': 'profile=normal&pid=14941729&var1=alpha&var2=alpha'},
 {'normal|production|var2_beta': 'profile=normal&pid=14941729&var2=beta'},
 {'normal|production|var2_alpha': 'profile=normal&pid=14941729&var2=alpha'},...

My issue

This isn't scalable to adding several more configuration dictionaries.

Let's say I now wanted to add another configuration dictionary, say, release. I'd have to add that new dict, plus amend the "total" comprehension like thus:

total = [
    {"{}|{}|{}|{}".format(pk, ek, tk, rk): {**pv, **ev, **tv, **rv}}
    for pk, pv in profile.items()
    for ek, ev in environment.items()
    for tk, tv in test_vars.items()
    for rk, rv in release_vars.items()
]

Which seems inelegant, especially when I could be dealing with 00's of configuration dictionaries.

Can anyone help devise something more scalable?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

夏日落 2025-01-18 10:07:36

你可以尝试这样的事情:

from itertools import product
def t(*args):
    counter = len(args)
    tmp  = [i.keys() for i in args]

    s =  {"|".join(i): [l[k] for l,k in zip(args,i)] for i in product(*tmp)}

    for k, v in s.items():
         s[k] = "&".join(["%s=%s"%(v1,v2) for j in v for v1,v2 in j.items()])
    return s

from pprint import pprint
pprint(t(profile, environment, test_vars))

结果:

{'normal|legacy|no_tests': 'profile=normal&id=123&var1=',
 'normal|legacy|var1+var2': 'profile=normal&id=123&var1=alpha&var2=alpha',
 'normal|legacy|var1:prod': 'profile=normal&id=123&var1=prod',
 'normal|legacy|var2_alpha': 'profile=normal&id=123&var2=alpha', ...

PS这不一定是最好的解决方案,但它可以扩展,祝你好运:)

you could try something like this :

from itertools import product
def t(*args):
    counter = len(args)
    tmp  = [i.keys() for i in args]

    s =  {"|".join(i): [l[k] for l,k in zip(args,i)] for i in product(*tmp)}

    for k, v in s.items():
         s[k] = "&".join(["%s=%s"%(v1,v2) for j in v for v1,v2 in j.items()])
    return s

from pprint import pprint
pprint(t(profile, environment, test_vars))

Result :

{'normal|legacy|no_tests': 'profile=normal&id=123&var1=',
 'normal|legacy|var1+var2': 'profile=normal&id=123&var1=alpha&var2=alpha',
 'normal|legacy|var1:prod': 'profile=normal&id=123&var1=prod',
 'normal|legacy|var2_alpha': 'profile=normal&id=123&var2=alpha', ...

P.S. This is not necessary the best solution, but it could be scaled, good luck :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文