Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/298.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 在展开字典时处理自引用_Python_Dictionary_Recursion - Fatal编程技术网

Python 在展开字典时处理自引用

Python 在展开字典时处理自引用,python,dictionary,recursion,Python,Dictionary,Recursion,给我一些任意的字典 mydict = { 'first': { 'second': { 'third': { 'fourth': 'the end' } } } } 我已经写了一个小程序,在回答另一个问题的过程中把它简化 def recursive_flatten(mydict): d = {} for k, v in mydict.items(

给我一些任意的字典

mydict = {
    'first': {
        'second': {
            'third': {
                'fourth': 'the end'
             }
         }
     }
}
我已经写了一个小程序,在回答另一个问题的过程中把它简化

def recursive_flatten(mydict):
    d = {}
    for k, v in mydict.items():
        if isinstance(v, dict):
            for k2, v2 in recursive_flatten(v).items():
                d[k + '.' + k2] = v2 
        else:
            d[k] = v
    return d
它起作用了,给了我想要的:

new_dict = recursive_flatten(mydict)

print(new_dict)
{'first.second.third.fourth': 'the end'}
而且应该适用于任何任意结构的词典。不幸的是,它没有:

mydict['new_key'] = mydict
现在,递归展平(mydict)将一直运行,直到堆栈空间用完。我试图弄明白如何优雅地处理自我引用(基本上,忽略或删除它们)。使事情复杂化的是,任何子字典都可能出现自引用。。。不仅仅是高层。我如何优雅地处理自我介绍?我可以想到一个可变的默认参数,但应该有更好的方法。。。对吧?


感谢指点,谢谢阅读。如果您有任何其他建议/改进,我欢迎您提出

我不确定您对“优雅”的定义是什么,但这可以通过对以前在对象ID的
集合中看到的内容进行簿记来实现:

class RecursiveFlatten:
    def __init__(self):
        self.seen = set()

    def __call__(self, mydict):
        self.seen.add(id(mydict))
        d = {}
        for k, v in mydict.items():
            if isinstance(v, dict):
                if id(v) not in self.seen:
                    self.seen.add(id(v))
                    for k2, v2 in self(v).items():
                        d[k + '.' + k2] = v2
            else:
                d[k] = v
        return d

def recursive_flatten(mydict):
    return RecursiveFlatten()(mydict)
测试它给了我我的期望

mydict = {
    'first': {
        'second': {
            'third': {
                'fourth': 'the end'
             }
         },
        'second2': {
            'third2': 'the end2'
        }
     }
}

mydict['first']['second']['new_key'] = mydict
mydict['new_key'] = mydict
print(recursive_flatten(mydict))
输出:


一种方法是使用和。注意,这个解决方案还使用生成器,这意味着我们可以在计算整个结果之前开始使用平坦的dict

def recursive_flatten (mydict):
  def loop (seen, path, value):

    # if we've seen this value, skip it
    if id(value) in seen:
      return

    # if we haven't seen this value, now we have
    else:
      seen.add(id(value))

    # if this value is a dict...
    if isinstance (value, dict):
      for (k, v) in value.items ():
        yield from loop(seen, path + [k], v)

    # base case
    else:
      yield (".".join(path), value)

  # init the loop    
  yield from loop (set(), [], mydict)
程序演示

mydict = {
    'first': {
        'second': {
            'third': {
                'fourth': 'the end'
             }
         }
     }
}

for (k,v) in recursive_flatten (mydict):
  print (k, v)

# first.second.third.fourth the end

mydict['new_key'] = mydict

for (k,v) in recursive_flatten (mydict):
  print (k, v)

# first.second.third.fourth the end
如果您希望看到自参考值的输出,我们可以做一些轻微的修改

# if we've seen this value, skip it
if (id(value) in seen):
  # this is the new line
  yield (".".join(path), "*self-reference* %d" % id(value))
  return
现在程序的输出将是

first.second.third.fourth the end
first.second.third.fourth the end
new_key *self-reference* 139700111853032

一种方法是把你遇到的每件事都放在字典里,边走边检查你以前没有见过的东西。另一种方法是保留两个指针,让其中一个走两步,另一个走一步。如果它们重合,就有一个循环。问题还在于接下来要做什么-中止或返回定义良好的内容。在Python中使用这样的类是常见的吗?对一个私有绑定进行本地化有点过分了,不是吗?我以前做过,idk如果我说这是过分了,但仔细想想,嵌套函数也可能达到同样的效果。这就是我在C++中生活了3年的原因。无论如何,你的方法肯定更好,不用担心。我自己也是Python新手,所以我不知道社区认为什么是惯用语言。看到一个对OP的原始代码进行最小修改的解决方案真是太棒了!
first.second.third.fourth the end
first.second.third.fourth the end
new_key *self-reference* 139700111853032