从嵌套的 python 字典生成所有组合并将它们隔离

Sur*_*ren -1 python combinations dictionary nested permutation

我的示例字典是:

sample_dict = {
    'company': {
        'employee': {
            'name': [
                {'explore': ["noname"],
                 'valid': ["john","tom"],
                 'boundary': ["aaaaaaaaaa"],
                 'negative': ["$"]}],
            'age': [
                {'explore': [200],
                 'valid': [20,30],
                 'boundary': [1,99],
                 'negative': [-1,100]}],
            'others':{
                'grade':[
                    {'explore': ["star"],
                     'valid': ["A","B"],
                     'boundary': ["C"],
                     'negative': ["AB"]}]}
    }
}}
Run Code Online (Sandbox Code Playgroud)

它是一个“后续”问题 ->拆分 python 字典以生成所有值组合
我想得到一个隔离的组合列表,如下所示

有效组合:[仅从有效数据列表中生成]
COMPLETE OUTPUT for VALID类别 :

{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'A'}}}
{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'B'}}}
{'company': {'employee': {'age': 20}, 'name': 'tom', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 20}, 'name': 'tom', 'others': {'grade': 'B'}}} 
{'company': {'employee': {'age': 30}, 'name': 'john', 'others': {'grade': 'A'}}}
{'company': {'employee': {'age': 30}, 'name': 'john', 'others': {'grade': 'B'}}}
{'company': {'employee': {'age': 30}, 'name': 'tom', 'others': {'grade': 'A'}}} 
{'company': {'employee': {'age': 30}, 'name': 'tom', 'others': {'grade': 'B'}}}
Run Code Online (Sandbox Code Playgroud)

负组合:[这里有点棘手,因为负组合也应该与“有效”池相结合,至少只有负值]
NEGATIVE 类别的完整输出:
=>[基本上,排除所有值都有效的组合 - 确保组合中至少有一个值来自负组]

{'company': {'employee': {'age': 20}, 'name': 'john', 'others': {'grade': 'AB'}}}
{'company': {'employee': {'age': -1}, 'name': 'tom', 'others': {'grade': 'A'}}}
{'company': {'employee': {'age': 100}, 'name': 'john', 'others': {'grade': 'A'}}}
{'company': {'employee': {'age': 30}, 'name': '$', 'others': {'grade': 'A'}}}
{'company': {'employee': {'age': 30}, 'name': '$', 'others': {'grade': 'AB'}}}
{'company': {'employee': {'age': -1}, 'name': '$', 'others': {'grade': 'AB'}}}
{'company': {'employee': {'age': 100}, 'name': '$', 'others': {'grade': 'AB'}}}
Run Code Online (Sandbox Code Playgroud)

在上面的输出中,在第一行中,通过保持所有有效值来测试等级是否为负值 AB。因此,没有必要生成与年龄相同的 30 岁,因为目的是仅测试负集。我们可以为其余参数提供任何有效数据。


边界组合类似于有效 -> 仅边界池内所有值的组合
探索:类似于负 - 与有效池混合,并且在所有组合中始终至少有一个探索值。

示例 dict - 修订版

sample_dict2 = {
    'company': {
        'employee_list': [
            {'employee': {'age': [{'boundary': [1,99],
                                   'explore': [200],
                                   'negative': [-1,100],
                                   'valid': [20, 30]}],
                          'name': [{'boundary': ['aaaaaaaaaa'],
                                    'explore': ['noname'],
                                    'negative': ['$'],
                                    'valid': ['john','tom']}],
                          'others': {
                              'grade': [
                                  {'boundary': ['C'],
                                   'explore': ['star'],
                                   'negative': ['AB'],
                                   'valid': ['A','B']},
                                  {'boundary': ['C'],
                                   'explore': ['star'],
                                   'negative': ['AB'],
                                   'valid': ['A','B']}]}}},
            {'employee': {'age': [{'boundary': [1, 99],
                                   'explore': [200],
                                   'negative': [],
                                   'valid': [20, 30]}],
                          'name': [{'boundary': [],
                                    'explore': [],
                                    'negative': ['$'],
                                    'valid': ['john', 'tom']}],
                          'others': {
                              'grade': [
                                  {'boundary': ['C'],
                                   'explore': ['star'],
                                   'negative': [],
                                   'valid': ['A', 'B']},
                                  {'boundary': [],
                                   'explore': ['star'],
                                   'negative': ['AB'],
                                   'valid': ['A', 'B']}]}}}
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

sample_dict2 包含字典列表。这里“员工”整个层次结构是一个列表元素,叶节点“等级”也是一个列表
此外,除了“有效”和“边界”之外,其他数据集可以是空的——[],我们也需要处理它们。
有效组合将类似于

{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','A']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','B']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','A']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','A']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','B']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','A']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'john', 'others': {'grade': ['A','B']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','A']}}]}}
{'company': {'employee_list':[{'employee': {'age': 20}, 'name': 'john', 'others': {'grade': ['A','B']}},{'employee': {'age': 1}, 'name': 'tom', 'others': {'grade': ['A','B']}}]}}
Run Code Online (Sandbox Code Playgroud)

加上员工索引 0 中年龄=30 和姓名=tom 的组合

cdl*_*ane 5

import itertools

def generate_combinations(thing, positive="valid", negative=None):

    """ Generate all possible combinations, walking and mimicking structure of "thing" """

    if isinstance(thing, dict):  # if dictionary, distinguish between two types of dictionary
        if positive in thing:
            return thing[positive] if negative is None else [thing[positive][0]] + thing[negative]
        else:
            results = []
            for key, value in thing.items():  # generate all possible key: value combinations
                subresults = []
                for result in generate_combinations(value, positive, negative):
                    subresults.append((key, result))
                results.append(subresults)
            return [dict(result) for result in itertools.product(*results)]

    elif isinstance(thing, list) or isinstance(thing, tuple):  # added tuple just to be safe
        results = []
        for element in thing:  # generate recursive result sets for each element of list
            for result in generate_combinations(element, positive, negative):
                results.append(result)
        return results

    else:  # not a type we know how to handle
        raise TypeError("Unexpected type")


def generate_invalid_combinations(thing):

    """ Generate all possible combinations and weed out the valid ones """

    valid = generate_combinations(thing)

    return [result for result in generate_combinations(thing, negative='negative') if result not in valid]


def generate_boundary_combinations(thing):

    """ Generate all possible boundary combinations """

    return generate_combinations(thing, positive="boundary")


def generate_explore_combinations(thing):

    """ Generate all possible explore combinations and weed out the valid ones """

    valid = generate_combinations(thing)

    return [result for result in generate_combinations(thing, negative='explore') if result not in valid]
Run Code Online (Sandbox Code Playgroud)

调用generate_combinations(sample_dict)返回:

[
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'B'}}}},
{'company': {'employee': {'age': 20, 'name': 'tom', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 20, 'name': 'tom', 'others': {'grade': 'B'}}}},
{'company': {'employee': {'age': 30, 'name': 'john', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 30, 'name': 'john', 'others': {'grade': 'B'}}}},
{'company': {'employee': {'age': 30, 'name': 'tom', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 30, 'name': 'tom', 'others': {'grade': 'B'}}}}
]
Run Code Online (Sandbox Code Playgroud)

调用generate_invalid_combinations(sample_dict)返回:

[
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'AB'}}}},
{'company': {'employee': {'age': 20, 'name': '$', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 20, 'name': '$', 'others': {'grade': 'AB'}}}},
{'company': {'employee': {'age': -1, 'name': 'john', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': -1, 'name': 'john', 'others': {'grade': 'AB'}}}},
{'company': {'employee': {'age': -1, 'name': '$', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': -1, 'name': '$', 'others': {'grade': 'AB'}}}},
{'company': {'employee': {'age': 100, 'name': 'john', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 100, 'name': 'john', 'others': {'grade': 'AB'}}}},
{'company': {'employee': {'age': 100, 'name': '$', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 100, 'name': '$', 'others': {'grade': 'AB'}}}}
]
Run Code Online (Sandbox Code Playgroud)

调用 generate_boundary_combinations(sample_dict) 返回:

[
{'company': {'employee': {'age': 1, 'name': 'aaaaaaaaaa', 'others': {'grade': 'C'}}}},
{'company': {'employee': {'age': 99, 'name': 'aaaaaaaaaa', 'others': {'grade': 'C'}}}}
]
Run Code Online (Sandbox Code Playgroud)

调用 generate_explore_combinations(sample_dict) 返回:

[
{'company': {'employee': {'age': 20, 'name': 'john', 'others': {'grade': 'star'}}}},
{'company': {'employee': {'age': 20, 'name': 'noname', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 20, 'name': 'noname', 'others': {'grade': 'star'}}}},
{'company': {'employee': {'age': 200, 'name': 'john', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 200, 'name': 'john', 'others': {'grade': 'star'}}}},
{'company': {'employee': {'age': 200, 'name': 'noname', 'others': {'grade': 'A'}}}},
{'company': {'employee': {'age': 200, 'name': 'noname', 'others': {'grade': 'star'}}}}
]
Run Code Online (Sandbox Code Playgroud)

修改后的解决方案(匹配修改后的问题)

import itertools
import random

def generate_combinations(thing, positive="valid", negative=None):

    """ Generate all possible combinations, walking and mimicking structure of "thing" """

    if isinstance(thing, dict):  # if dictionary, distinguish between two types of dictionary
        if positive in thing:
            if negative is None:
                return thing[positive]  # here it's OK if it's empty
            elif thing[positive]:  # here it's not OK if it's empty
                return [random.choice(thing[positive])] + thing[negative]
            else:
                return []
        else:
            results = []
            for key, value in thing.items():  # generate all possible key: value combinations
                results.append([(key, result) for result in generate_combinations(value, positive, negative)])
            return [dict(result) for result in itertools.product(*results)]

    elif isinstance(thing, (list, tuple)):  # added tuple just to be safe (thanks Padraic!)
        # generate recursive result sets for each element of list
        results = [generate_combinations(element, positive, negative) for element in thing]
        return [list(result) for result in itertools.product(*results)]

    else:  # not a type we know how to handle
        raise TypeError("Unexpected type")


def generate_boundary_combinations(thing):

    """ Generate all possible boundary combinations """

    valid = generate_combinations(thing)

    return [result for result in generate_combinations(thing, negative='boundary') if result not in valid]
Run Code Online (Sandbox Code Playgroud)

generate_invalid_combinations()generate_explore_combinations()以前一样。细微差别:

它不是在否定评估中从有效数组中获取第一项,而是从有效数组中随机获取一项。

像这样的项目的值'age': [30]作为列表返回,因为它们是如何指定的:

'age': [{'boundary': [1, 99],
    'explore': [200],
    'negative': [-1, 100],
    'valid': [20, 30]}],
Run Code Online (Sandbox Code Playgroud)

如果您想要'age': 30更早的输出示例,请相应地修改定义:

'age': {'boundary': [1, 99],
    'explore': [200],
    'negative': [-1, 100],
    'valid': [20, 30]},
Run Code Online (Sandbox Code Playgroud)

边界属性现在被视为“负”值之一。

仅供参考,这次我不打算生成所有输出:调用generate_combinations(sample_dict2)返回结果如下:

[
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [30]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'B']}, 'age': [20]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['A', 'B']}, 'age': [30]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['john'], 'others': {'grade': ['A', 'A']}, 'age': [20]}}, {'employee': {'name': ['john'], 'others': {'grade': ['B', 'A']}, 'age': [20]}}]}},
...
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['A', 'B']}, 'age': [30]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'A']}, 'age': [20]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'A']}, 'age': [30]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [20]}}]}},
{'company': {'employee_list': [{'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}, {'employee': {'name': ['tom'], 'others': {'grade': ['B', 'B']}, 'age': [30]}}]}}
]
Run Code Online (Sandbox Code Playgroud)