平面比嵌套好:如何处理深度嵌套的词典



在我作为工程师(而非软件(的工作中,有时我必须用Python编程。在教程之后,我了解了字典以及如何使用它们来存储数据,它们很快等等。

我有嵌套的字典,可以达到7级,比如:

mydict['level1']['level2']['level3']['level4']['level5']['level6']['level7']

我之所以有这些小怪物,是因为我用一个库解析了一个文档,该库返回了以下内容:

components['comp1']['comp_name']
components['comp1']['comp_dimension']
components['comp1']['subcomponents']['subcomp1']
components['comp1']['subcomponents']['subcomp1']['comp_name1']
etc.

我还有其他的格言也嵌套得很深。

我面临的问题是,我需要迭代到最后一个级别来获得和过滤结果,因为我事先不知道密钥,所以我像下面的伪代码一样迭代:

示例1:漂亮的

filter_subcomps = ["comp1", "comp10"]
filter_value = 10.0
for component in components
comp_name = components[component]['comp_name']
comp_dimension = components[component]['comp_dimension']
if components[component].get('subcomponents', False):
subcomp_keys = filter_subcomps if filter_subcomps else components[component]['subcomponents'].keys()
for subcomponent in subcomp_keys:
etc etc
if value > X:
return value

示例2:有点丑(下降3级,还有4级…(:

# I changed the variable names and cut somethings to give a shorter example. 
# So there probably are some errors that you should ignore. 
# The goal is to show the ugliness of my code :)
def get_peak_xy_position(self):
peak_final_lst = list()
x_coord_list = list()
y_coord_list = list()
filter_comp = self.params['options']['filter_comp']
filter_comp_parent = self.params['options']['comp_parent']
filter_peak = self.params['options']['filter_peak']
for xy_coord in self.xy:
peak_xy_list = [0]
x_coord = float(xy_coord.split('_')[0])
y_coord = float(xy_coord.split('_')[1])
if self.components.get(xy_coord, False):
comp_keys = filter_comp if filter_comp else self.components[xy_coord].keys()
for comp in comp_keys:
if self.components[xy_coord].get(comp, False):
if self.components[xy_coord][comp].get('comp_parents', False):
comp_parent_keys = filter_comp_parent if filter_comp_parent else self.components[xy_coord][comp]['comp_parents'].keys()
for parent in comp_parent_keys:
if self.components[xy_coord][comp]['comp_parents'][parent].get('comp_signal', False):
peak_signal = self.components[xy_coord][comp]['comp_parents'][parent]['comp_signal']['peak']
final_peak = current_peak_signal
if filter_peak:
final_peak = current_peak_signal if filter_peak <= current_peak_signal else 0
peak_xy_list.append(final_current)
peak_final_lst.append(max(peak_final_lst))
x_coord_list.append(x_coord)
y_coord_list.append(y_coord)
return x_coord_list, y_coord_list, peak_final_list

这些是一个相当简单的例子,有时代码会有超过10级的缩进,这看起来很糟糕,我不得不水平滚动页面。除此之外,我甚至很难在几天或几周后阅读代码。

我读过一些人的教程,他们将表格数据转换为嵌套dict,反之亦然,甚至还有人使用xpath访问dict键。

无论如何,遵循python的禅宗,我当然不尊重"扁平比嵌套好";因为我的代码进入了天文级别的缩进

我想将所有嵌套的dict转换为SQLite,并使用SQL语言进行查询,而不是这些丑陋的for循环和if条件。那么,我该怎么办?如何处理Python中的嵌套dict,同时尽可能保持代码的平面化?我在这里有点迷路了。

PS:我的问题与"扁平比嵌套更好"无关——对于数据和代码?因为我已经有了嵌套很深的dicts。我想知道如何处理这些dict、查询/筛选值等,同时拥有一个平面代码。

我不会更改数据结构。如果这就是你得到的,并且它很好地模拟了问题,那就顺其自然吧。

把你的代码分解成一些小函数,这些小函数在结构中占据更深的层次。


def filter_components(components, keys, value):
# if key is not needed, use .values()
for key, component in components.items():
if 'subcomponents' in component:
filter_subcomponent(component['subcomponents'], keys, value)

def filter_subcomponents(subcomps, keys, values):
for subcomp in subcombs.values():
# do stuff 

如果更复杂,就多拆分。完成部分工作的小型、易读的函数。

有几种方法可以解决这个问题:

  1. 压平结构。如果您认为平面表的处理速度更快,那么将结构平面化为类或结构实例的平面列表,然后处理该平面列表可能是有意义的
  2. 如果结构在各个级别上是统一的(即使每个级别的名称不同(,则可以使用简单的递归。您将拥有一个函数,该函数将检查某一级别上的项是否有子项,并在每个子项存在的情况下调用自己,或者为最终级别的项调用数据处理函数。如果子组件名称不同,您可以有一个这样的名称数组,上面写着"在级别1上,项目被称为"comp*",在级别2上-"subc*",依此类推
  3. 如果级别需要完全不同的处理,请为每个级别引入单独的功能

最新更新