【问题标题】:Recursive method changing dictionary during iteration迭代期间的递归方法更改字典
【发布时间】:2018-06-19 00:01:16
【问题描述】:

尝试在类中使用递归方法来扁平化嵌套的 OrderedDicts。结果是 RuntimeError:字典在迭代期间改变了大小

我得到了一个 OrderedDicts 列表。大多数 OrderedDict 是简单的 Key:string-value 属性,但有些值包含另一个 OrderedDict。这种嵌套可以下降几个层次。这是一个非常简化的示例:

records = [
    OrderedDict([
        ('rec-1_field-1', 'r1f1_value'),
        ('rec-1_field-2', 'r1f2_value'),
        ('rec-1_nest-1', OrderedDict([
            ('n1_field-1', 'n1f1_value'),
            ('n1_field-2', 'n1f2_value')
            ])
         )
        ]),
    OrderedDict([
        ...
        ])
]

我的目标是取消嵌套这些 OrderedDicts,以便将上述内容开始转换为这个(注意我试图获得的“higherKey.lowerKey”命名法):

flatRecords = [
    {'rec-1_field-1':'r1f1_value',
    'rec-1_field-2':'r1f2_value',
    'rec-1_nest-1.n1_field-1':'n1f1_value',
    'rec-1_nest-1.n1_field-2':'n1f2_value'},
    ...
    ]

这是我的代码的简化版本。我将每个 OrderedDict 提供给一个在找到嵌套的 OrderedDict 时递归的方法。我想我在递归中覆盖了我的 flatRecord Dict 但无法确定如何更正。

class unNested():
    def __init__(self):
        pass
    def flatResults(self, OD):
        self.OD = OD
        self.flattenedRecords = []
        for eachRecord in self.OD:
            self.flattenedRecords.append(self.flatten(eachRecord))
        return self.flattenedRecords
    def flatten(self, record):
        self.record = record
        self.flatRecord = {}
        for eachKey in self.record:
            if isinstance(self.record[eachKey], dict):
                self.subRecord = self.flatten(self.record[eachKey])
                for eachSub in self.subRecord:
                    self.key = eachKey + '.' + eachSub
                    self.flatRecord[self.key] = self.record[eachSub]
            else:
                self.flatRecord[eachKey] = self.record[eachKey]
        return self.flatRecord

所以下面的 sn-p 会导致“RuntimeError: dictionary changed size during iteration”

records = [
    OrderedDict([
        ('rec-1_field-1', 'r1f1_value'),
        ('rec-1_field-2', 'r1f2_value'),
        ('rec-1_nest-1', OrderedDict([
            ('rec-1_nest-1_field-1', 'r1n1f1_value'),
            ('rec-1_nest-1_field-2', 'r1n1f2_value')
            ])
         )
        ]),
    OrderedDict([
        ('rec-2_field-1', 'r2f1_value'),
        ('rec-2_field-2', 'r2f2_value'),
        ('rec-2_nest-1', OrderedDict([
            ('rec-2_nest-1_field-1', 'r2n1f1_value'),
            ('rec-2_nest-1_field-2', 'r2n1f2_value')
            ])
         )
        ])
    ]
crush = unNested()
crush.flatResults(records)

我确定这是一个业余错误,但我很想听听任何想法或指导。谢谢!

【问题讨论】:

  • 为什么有一个类,为什么要将所有代码的状态存储在实例变量中?您的递归调用将踩踏彼此的状态,因为它们共享实例变量。
  • 要添加到@user2357112 的评论中,一个简单的解决方法是在您定义self.subRecord 的行上使用.copy()。但我不确定你的逻辑是否会输出你想要的结果。

标签: python python-3.x recursion ordereddictionary


【解决方案1】:

您可以使用扁平化方法:

from collections import OrderedDict
records = [OrderedDict([('rec-1_field-1', 'r1f1_value'), ('rec-1_field-2', 'r1f2_value'), ('rec-1_nest-1', OrderedDict([('n1_field-1', 'n1f1_value'), ('n1_field-2', 'n1f2_value')]))])]
def flatten(d, last=''):
   for a, b in d.items():
      if not isinstance(b, OrderedDict):
         yield (f'{last}.{a}' if last else a, b)
      else:
         yield from flatten(b, last = a)

final_result = dict(flatten(records[0]))

输出:

{'rec-1_field-1': 'r1f1_value', 'rec-1_field-2': 'r1f2_value', 'rec-1_nest-1.n1_field-1': 'n1f1_value', 'rec-1_nest-1.n1_field-2': 'n1f2_value'}

为列表中的每个元素创建一个扁平结构:

final_result = [dict(flatten(i)) for i in records]

【讨论】:

  • 是的……那好多了。谢谢,伙计!
  • @JClark 很高兴为您提供帮助!
猜你喜欢
  • 2021-11-21
  • 2019-12-02
  • 1970-01-01
  • 2021-07-26
  • 2022-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-15
相关资源
最近更新 更多