检查所有属性是否作为嵌套元组的一个(且仅一个)索引中的dict键存在

时间:2018-04-06 13:00:16

标签: python python-3.x

我有以下Python元组:

my_tuple = ( "key1", ("nested_key1", "nested_key2"), "key3")

我需要测试dict是否包含"key1"("nested_key1", "nested_key2")"key3"中的所有元素。如果任何根元组的索引中的所有元素都匹配,那么如果其他索引中没有其他匹配,则算法应仅评估为True。如果元组中没有指定其他键,则可以忽略这些键以进行匹配。

意思是......

这些应该返回True:

matching_dict_root = {"key1": 1}
matching_dict_nested = {"nested_key1": 2, "nested_key2": 3}
unspecified_keys_are_allowed = {"key1": 1, "99problems": 99}

这些应该是假的:

too_many = {"key1": 1, "nested_key1": 1, "nested_key2": 2}
also_wrong = {"key1": 1, "nested_key2": 1}

可以假设(对于我目前的情况,但一般的解决方案是最受欢迎的):

  • 只有1个嵌套级别
  • 所有个别属性(在所有深度)都是全球唯一的

Python-3.6,Python-2.7也很有用,但不是必需的。如果可能的话(我认为是,并且我将自己踢),标准。库。仅

2 个答案:

答案 0 :(得分:1)

所以喜欢:

sum( keys in D if not isinstance(keys, tuple) 
               else all( key in D for key in keys )
     for keys in my_tuple ) == 1

sum( ) == 1而不是any( )的原因是:

  

如果其他索引中没有其他匹配项,则仅评估为True

这意味着my_tuple中只应有一个True的索引,其余索引必须为False

答案 1 :(得分:1)

让我疯了,但这里是......

要获得一个扁平的元组列表,我们使用Flatten (an irregular) list of lists中的辅助函数:

def flatten(l):
    for el in l:
        if isinstance(el, collections.Iterable) and not isinstance(el, (str, bytes)):
            yield from flatten(el)
        else:
            yield el

这将允许使用frozenset.isdisjoint()针对展平列表的子列表测试无效的交叉点。

在扩展@DanD的有用解决方案之后,最终解决方案是:

def all_attributes_exist_with_null_intersection(iterable, d):
    return sum((i in d if not isinstance(i, tuple) else (all(sub_i in d for sub_i in i)))
               and frozenset(d.keys()).isdisjoint(flatten([x for x in i if x != i]))
               for i in iterable) == 1

<强>试验:

sample_tuple = ("key1", ("nested_key1", "nested_key2"), "key3")

true_tests = [
    {"key1": 1},
    {"nested_key1": 2, "nested_key2": 3},
    {"key1": 1, "99problems": 99}
]

false_tests = [
    {"key1": 1, "nested_key1": 1, "nested_key2": 2},
    {"key1": 1, "nested_key2": 1}
]

trues = [all_attributes_exist_with_null_intersection(sample_tuple, d) for d in true_tests]
falses = [all_attributes_exist_with_null_intersection(sample_tuple, d) for d in false_tests]

print("Trues:\n{trues}\n\nFalses:\n{falses}".format(
    trues=trues,
    falses=falses
)

<强>输出:

Trues:
[True, True, True]

Falses:
[False, False]

<强>注意事项:

  • 帮助函数中的yield from需要Python 3.3