如何高效验证dict1是dict2的子集?键为字符串值为整数
问题
我想写高效代码判断一个字典是否是另一个字典的子集。两个字典都是字符串键、整数值。dict1被视为子集的条件是:没有dict2不存在的键,且所有键对应的值都小于等于dict2的对应值。
我试了test_dict.items() <= test_dict2.items(),但在下面的测试中返回False:
test_dict = { 'a':1, 'c':2 } test_dict2 = { 'a':1, 'b':2, 'c':3 } print(test_dict.items() <= test_dict2.items()) # 输出False
我自己实现了一个函数,但不确定效率够不够:
def test(request_totals, mongo_totals, max_limit=100): outdated = dict() sharedKeys = set(request_totals.keys()).intersection(mongo_totals.keys()) unsharedKeys = set(request_totals) - set(mongo_totals) # 检查MongoDB不能有独有的集合 if set(mongo_totals) - set(request_totals) != set(): raise AttributeError(f'''mongo_totals does not appear to be a subset of request_totals. Found: {set(mongo_totals) - set(request_totals)}''') # 更新outdated字典,存储需要更新的MongoDB集合键值对 for key in sharedKeys: if request_totals[key] > mongo_totals[key]: outdated.update({key : range(mongo_totals[key], request_totals[key])}) elif request_totals[key] < mongo_totals[key]: raise AttributeError( f'mongo_total for {key}: {mongo_totals[key]} exceeds request_totals for {key}: {request_totals[key]}') return outdated test(request_totals, mongo_totals)
在生成更新管理对象前做这些对比感觉太繁琐,有没有更优的实现方式?
回答
为什么items()子集判断失效
Python中dict.items()的<=判断是检查所有键值对完全存在于另一个字典中,而不是值的大小关系。比如你的例子里test_dict的'c':2不在test_dict2.items()里(后者是'c':3),所以返回False,这不符合你的需求。
高效的子集判断函数
如果只需要判断dict1是否是dict2的子集(满足无独有键、值全≤),可以用下面的简洁实现,利用Python字典的高效操作:
def is_subset_dict(dict1, dict2): # 第一步:检查dict1的所有键都在dict2中(O(1)时间复杂度,因为字典键是哈希表) if not dict1.keys() <= dict2.keys(): return False # 第二步:检查每个键对应的值都≤,生成器表达式结合all()会短路求值,遇到不满足的立刻返回 return all(dict1[key] <= dict2[key] for key in dict1)
针对你的业务场景优化函数
你的函数不仅要判断子集关系,还要检查反向的键存在性(mongo_totals不能有额外键)、生成outdated字典,下面是优化后的版本,减少冗余的集合操作,提升效率:
def check_and_get_outdated(request_totals, mongo_totals): # 检查mongo_totals是否有request_totals没有的键 extra_keys = mongo_totals.keys() - request_totals.keys() if extra_keys: raise AttributeError(f"mongo_totals包含request_totals不存在的键: {extra_keys}") outdated = {} # 直接遍历request_totals的键值对,避免额外的集合交集操作 for key, req_val in request_totals.items(): mongo_val = mongo_totals[key] if req_val > mongo_val: outdated[key] = range(mongo_val, req_val) elif req_val < mongo_val: raise AttributeError(f"mongo_totals中键'{key}'的值{mongo_val}超过request_totals的{req_val}") return outdated
优化点说明:
- 利用字典
keys()的集合操作直接求差集,比手动转set更简洁高效 - 直接遍历
request_totals.items(),无需先计算共享键,减少一次集合交集的开销 - 字典的键查找是O(1)操作,比集合查找效率一致但更贴合业务逻辑
- 遇到不符合条件的情况立刻抛出异常,短路后续不必要的遍历
内容的提问来源于stack exchange,提问作者MrChadMWood
相关产品推荐
相关产品推荐

