查找嵌套字典中可能存在于不同位置的不匹配值的最佳方法



所以我有一个字典,看起来如下:

{
"tigj09j32f0j2": {
"car": {
"lead": {
"version": "1.1"
}
},
"bike": {
"lead": {
"version": "2.2"
}
},
"jet_ski": {
"lead": {
"version": "3.3"
}
}
},
"fj983j2r9jfjf": {
"car": {
"lead": {
"version": "1.1"
}
},
"bike": {
"lead": {
"version": "2.3"
}
},
"jet_ski": {
"lead": {
"version": "3.3"
}
}
}
}

包含carbikejet_ski的不同字典的数量可能很大,而不是像我的示例中那样只有两个。不同车型的数量也可以大得多。我的目标是在不同的字典之间找到给定类型的车辆version中的不匹配。例如,对于bike,两个字典之间的version是不同的。

我目前的做法是遍历字典中的所有子字典,然后查找版本。我将版本保存在一个包含车辆类型和版本的类字典中,然后开始与之进行比较。我相信有一种更优雅、更蟒蛇的方法可以做到这一点,如果有任何反馈,我将不胜感激!

以下是我正在做的事情:

def is_version_issue(vehicle_type: str, object_json: dict):
issue = False
for object_id in object_json:
current_object = object_json.get(object_id)
if vehicle_type in current_object:
current_vehicle_version = current_object.get(vehicle_type).get("lead").get("version")
# vehicles is a class dictionary that contains the vehicles I am looking for
if self.vehicles[vehicle_type]:
if self.vehicles[vehicle_type] == current_vehicle_version:
issue = False
continue
else:
return True
self.vehicles[vehicle_type] = current_vehicle_version
issue = False
return issue

好吧,您的解决方案还不错。我建议改进以下几点。

直接迭代子字典

您似乎根本不使用键(object_id),所以您不妨通过dict.values进行迭代。

不需要issue变量

你可以只返回你的旗帜一次";发行";则在循环结束时返回相反的结果。

减少缩进

如果不存在vehicle_type,则在循环中使用continue以减少缩进。

决定哪些假设是合理的

如果您知道每个车辆子字典都有lead密钥,下面的子字典将有version密钥(这意味着您多次使用dict.get而不首先检查None),只需使用常规字典下标符号([])。

不需要类词典

如果您在调用函数时正在检查特定的车辆类型,则不需要该字典(据我所知)。您只需要一个局部变量来保存该类型的最后一个已知版本号。

语义学

这可能是个人偏好的问题,但我会设计返回True的函数,如果一切都是";精细";以及CCD_ 18(如果某处存在失配)。

指定类型参数

如果您已经花时间使用类型注释,那么应该花时间正确地指定泛型。当然,在这种情况下,如果你的字典嵌套更深,它可能会变得很难处理,但在那种情况下,你至少可以使用dict[str, Any]

对重复键使用常量

为了减少出错的空间,我喜欢为代码中具有固定含义并重复使用的字符串定义常量。该模式似乎或多或少是固定的,因此您可以定义一次键,然后在整个代码中使用常量。这还有一个额外的好处,即如果架构由于某种原因发生了更改,并且其中一个键被重命名(例如从versionver或类似的内容),则很容易修复。

显然,在这种超级简单的情况下,这是过分的,但如果您在整个代码的更多地方引用相同的键,我强烈建议采用这种做法。

建议实施

KEY_LEAD = "lead"
KEY_VERSION = "version"
def versions_consistent(
vehicle_type: str,
data: dict[str, dict[str, dict[str, dict[str, str]]]]
) -> bool:
version_found: str | None = None
for vehicles in data.values():
vehicle = vehicles.get(vehicle_type)
if vehicle is None:
continue
if version_found is None:
version_found = vehicle[KEY_LEAD][KEY_VERSION]
elif version_found != vehicle[KEY_LEAD][KEY_VERSION]:
return False
return True

奖金

您可以考虑在最后执行一个额外的检查,看看version_found是否仍然是None。这可能表明传递了一个无效的vehicle_type(例如,由于打字错误)。在这种情况下,您可以引发一个异常。

另一种选择是,如果您提前知道车辆类型,则可以通过提前将它们再次定义为常量,然后在函数的开头检查(如果传递了有效类型)来避免这种情况。

最后,您不仅可以考虑返回bool,还可以考虑实际保存某些数据结构中的不匹配/不一致,并返回该数据以指示特定车型的哪些ID具有哪些版本。

所以它也可能看起来像这样:

ALLOWED_VEHICLES = {"car", "bike", "jet_ski"}
def get_version_id_mapping(
vehicle_type: str,
data: dict[str, dict[str, dict[str, dict[str, str]]]]
) -> dict[str, set[str]]:
if vehicle_type not in ALLOWED_VEHICLES:
raise ValueError(f"{vehicle_type} is not a valid vehicle type")
version_id_map: dict[str, set[str]] = {}
for obj_id, vehicles in data.items():
vehicle = vehicles.get(vehicle_type)
if vehicle is None:
continue
ids = version_id_map.setdefault(vehicle["lead"]["version"], set())
ids.add(obj_id)
return version_id_map

调用get_version_id_mapping("bike", d)(d是您的示例数据)会得到以下结果:

{'2.2':{'tigj09j32f0j2'},'2.3':{'fj983j2r9jfjfj'}}

jet_ski调用它会得到以下结果:

{'3.3':{'fj983j2r9jfjfj','tigj09j32f0j2'}}

因此,通过检查输出字典的长度,您可以看到是否存在不一致(长度> 1)。

奖金2

仔细想想,如果你想对整个数据集的每种类型的车辆进行检查,这一切都可以一次性完成:

def vehicle_type_versions(
data: dict[str, dict[str, dict[str, dict[str, str]]]]
) -> dict[str, dict[str, set[str]]]:
output: dict[str, dict[str, set[str]]] = {}
for obj_id, vehicles in data.items():
for vehicle_type, vehicle_data in vehicles.items():
sub_dict = output.setdefault(vehicle_type, {})
ids = sub_dict.setdefault(vehicle_data["lead"]["version"], set())
ids.add(obj_id)
return output

在您的示例数据上调用此操作会产生以下输出:

{‘like’:{‘2.2':{’tigj09j32f0j2’},‘2.3':{{‘fj983j2r9jfjf’}},"car":{'1.1':{'fj983j2r9jfjf","tigj09j32f0j2"},'jet_ski':{'3.3':{'fj983j2r9jfjfj','tigj09j32f0j2'}}}
def is_version_issue(vehicle_type: str, object_json: dict):
current_object = object_json[object_id]
for object_id in current_object:
if vehicle_type in object_json[object_id]:
current_vehicle_version = current_object[vehicle_type]["lead"]["version"]
# vehicles is a class dictionary that contains the vehicles I am looking for
if self.vehicles[vehicle_type]:
if self.vehicles[vehicle_type] != current_vehicle_version:
return True
return False

不,我认为这是最合乎逻辑的方式,我认为你有一些冗余,但这对我来说是有意义的。还有一些其他问题,你不清楚自己是如何使用dict的。

我也不会使用临时current_变量,但如果您使用调试器,它们是很好的。

相关内容

  • 没有找到相关文章

最新更新