获取具有限制的Python字典的所有子集

时间:2017-06-05 20:43:24

标签: python dictionary combinations

我有以下字典:

intervals = {'param1': [0, 1],
             'param2_hi': [4, 5, 6, 7, 8, 9],
             'param2_lo': [0, 1, 2, 3, 4, 5],
             'param3_hi': [9, 10, 11, 12, 13, 14, 15],
             'param3_lo': [5, 6, 7, 8, 9, 10],
             'param4': [0, 1],
             'param5_hi': [4, 5, 6, 7, 8, 9],
             'param5_lo': [0, 1, 2, 3, 4, 5]}

如何创建此词典的所有可能子集,其中我必须正好具有每个数字x中的一个用于' paramx'?这意味着我只能为param1(_lo或_hi)创建一个条目,为param2(_lo或_hi)创建一个条目,依此类推,并且每个子集必须包含没有_lo或_hi的每个param。

以下是两个可能的子集:

subset_one = {'param1': [0, 1],
              'param2_hi': [4, 5, 6, 7, 8, 9],
              'param3_hi': [9, 10, 11, 12, 13, 14, 15],
              'param4': [0, 1],
              'param5_hi': [4, 5, 6, 7, 8, 9]}

subset_two = {'param1': [0, 1],
              'param2_lo': [0, 1, 2, 3, 4, 5],
              'param3_lo': [5, 6, 7, 8, 9, 10],
              'param4': [0, 1],
              'param5_lo': [0, 1, 2, 3, 4, 5]}

# Example of mixed '_hi' and '_lo' intervals
subset_three = {'param1': [0, 1],
                'param2_lo': [0, 1, 2, 3, 4, 5],
                'param3_hi': [9, 10, 11, 12, 13, 14, 15],
                'param4': [0, 1],
                'param5_lo': [0, 1, 2, 3, 4, 5]}

...

注意:我想保留键值对。

编辑:添加subset_three以显示混合' _lo'和' _hi'间隔。

5 个答案:

答案 0 :(得分:2)

在大多数情况下,您可以使用以下 dict 理解:

subset_1 = {k:v for k,v in intervals.items() if k.endswith('_hi') or not k.endswith('_lo')}
subset_2 = {k:v for k,v in intervals.items() if k.endswith('_lo') or not k.endswith('_hi')}

print(subset_1)
print(subset_2)

输出:

{'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param4': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9]}
{'param2_lo': [0, 1, 2, 3, 4, 5], 'param1': [0, 1], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param4': [0, 1], 'param5_lo': [0, 1, 2, 3, 4, 5]}

答案 1 :(得分:1)

我认为collections.defaultdictitertools.product在这里都很有用。首先,构建一个池,根据它们的开始对键进行排序。然后,构建这些箱的笛卡尔积。

from collections import defaultdict
from itertools import product

pool = defaultdict(list)
for key in intervals:
    base = key.split('_')[0]
    pool[base].append(key)

subsets = [{key: intervals[key] for key in keys} for keys in product(*pool.values())]

# {'param2_lo': [0, 1, 2, 3, 4, 5], ... , 'param1': [0, 1]}
# {'param5_lo': [0, 1, 2, 3, 4, 5], ..., 'param2_hi': [4, 5, 6, 7, 8, 9]}
# and so on...

答案 2 :(得分:1)

我相信您希望itertools.product应用于参数中的五个选项集:

choices = [
    ['param1'],
    ['param2_lo', 'param2_hi'],
    ['param3_lo', 'param3_hi'],
    ['param4'],
    ['param5_lo', 'param5_hi']
]

for permute in itertools.product(*choices):
    ....

这足以让你前进吗?

答案 3 :(得分:0)

我认为最好的工具是itertools.product,一个解决方案是:

intervals = {'param1': [0, 1],
             'param2_hi': [4, 5, 6, 7, 8, 9],
             'param2_lo': [0, 1, 2, 3, 4, 5],
             'param3_hi': [9, 10, 11, 12, 13, 14, 15],
             'param3_lo': [5, 6, 7, 8, 9, 10],
             'param4': [0, 1],
             'param5_hi': [4, 5, 6, 7, 8, 9],
             'param5_lo': [0, 1, 2, 3, 4, 5]}


import itertools

def get_subsets(intervals):

   params_list = set(key.split('_')[0] for key in intervals.keys())

   list_keys = [[x for x in intervals.keys() if x.startswith(param)] for param in params_list]

   subsets = [{x : intervals[x] for x in sublist} for sublist in itertools.product(*list_keys)]

   return subsets

get_subsets(intervals)

# [{'param2_lo': [0, 1, 2, 3, 4, 5], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param1': [0, 1], 'param4': [0, 1]}, {'param2_lo': [0, 1, 2, 3, 4, 5], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param1': [0, 1], 'param4': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9]}, ...

答案 4 :(得分:0)

您可以使用此示例中的groupby模块中的productitertools来列出所有可能的组合:

from itertools import groupby, product

intervals = {'param1': [0, 1],
             'param2_hi': [4, 5, 6, 7, 8, 9],
             'param2_lo': [0, 1, 2, 3, 4, 5],
             'param3_hi': [9, 10, 11, 12, 13, 14, 15],
             'param3_lo': [5, 6, 7, 8, 9, 10],
             'param4': [0, 1],
             'param5_hi': [4, 5, 6, 7, 8, 9],
             'param5_lo': [0, 1, 2, 3, 4, 5]}


sub = []

for _,v in groupby(sorted(intervals.keys()), lambda x: x[5]):
    # Or:
    # sub.append(list(v))
    sub.append(sorted(list(v)))


for k in product(*sub):
    print({j:intervals[j] for j in k})
    print("------")

输出:

{'param1': [0, 1], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param4': [0, 1]}
------
{'param1': [0, 1], 'param3_hi': [9, 10, 11, 12, 13, 14, 15], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param4': [0, 1]}
------
{'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param4': [0, 1]}
------
{'param1': [0, 1], 'param2_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param4': [0, 1]}
------
....
------

{'param4': [0, 1], 'param1': [0, 1], 'param5_hi': [4, 5, 6, 7, 8, 9], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param2_lo': [0, 1, 2, 3, 4, 5]}
------
{'param4': [0, 1], 'param1': [0, 1], 'param5_lo': [0, 1, 2, 3, 4, 5], 'param3_lo': [5, 6, 7, 8, 9, 10], 'param2_lo': [0, 1, 2, 3, 4, 5]}
------