如何在递归中替换dict中的值,直到值中没有键为止?

时间:2012-04-16 05:06:37

标签: python recursion dictionary

我有dict这样:

d = {'a':'b+c', 'b':'f+g', 'f':'y+u'}

我想递归地替换也是键的值中的字母,所以我最终得到:

d = {'a':'y+u+g+c', 'b':'y+u+g', 'f':'y+u'}

我尝试使用此代码:

def getval(key,d):
    if d.has_key(key):
    temp=re.findall('\w+',d[key])
    for i in range(len(temp)):
        if d.has_key(temp[i]):
            getval(temp[i],d)
        else:
            continue

for k,v in d.iteritems():
    temp=re.findall('\w+',d[k])
    for i in range(len(temp)):
        if d.has_key(temp[i]):
            getval(temp[i],d)

但它不起作用。我该怎么做?我真正的字典要大得多,但绝对不包含任何循环。

4 个答案:

答案 0 :(得分:1)

我实际上不确定递归是否是最合适的方法,这里是一个解决方案,在循环中进行替换,直到所有替换都不会更改当前值:

import re

def make_replacements(d):
    r = d.copy()
    regex = dict((k, re.compile(r'\b' + re.escape(k) + r'\b')) for k in r)
    for k in r:
        done = False
        while not done:
            done = True
            for k2 in r:
                n = regex[k2].sub(r[k2], r[k])
                if n != r[k]:
                    r[k] = n
                    done = False
    return r

print make_replacements({'a': 'b+c', 'b': 'f+g', 'f': 'y+u'})
# {'a': 'y+u+g+c', 'b': 'y+u+g', 'f': 'y+u'}

请注意,这不会检测输入中的任何循环,因此如果你给它类似{'a':'b+c','b':'c+a','c':'a+b'}的东西,它将进入一个无限循环(尽管听起来这应该永远不会发生在你的评论中)。

答案 1 :(得分:0)

您需要将该代码放在一个函数中。然后,您的注释行应该在您想要替换的任何内容上调用该函数,将其放入字符串中,并将结果分配到dict中。

答案 2 :(得分:0)

  • 这是一个迭代过程,带有多次迭代的熔丝来检查互无限替换。
  • 使用正则表达式将字符串拆分为多个分隔符
  • 将字符串规范化为 删除空格。
  • 逃离令牌,因此您无需逃脱 分隔符

尝试以下实施方案。

>>> def replace(d,delims,limit=5):
    #Remove any whitespace characters
    d=dict((k,v.translate(None,string.whitespace)) for k,v in d.iteritems())
    #Escape the regex tokens
    delims=re.escape(delims)
    for i in range(limit): #Loop Limit, to prevent infinite Loop
        changed=False
        for k,v in d.iteritems():
            #Its best to use regex if multiple tokens is involved
            r="+".join(d.get(e,e) for e in re.split(delims,v))
            if r!=v:
                #Break if no change in any iteration
                changed=True
            d[k]=r
        if not changed:
            break
    return d

>>> replace(d,"+")
{'a': 'y+u+g+c', 'b': 'y+u+g', 'f': 'y+u'}

答案 3 :(得分:0)

像这样的迭代方法的问题是它们的运行时对嵌套深度和dict中项目的顺序非常敏感。此递归版本以线性时间运行,结果为dict中的“段”总数,其中段是表达式的一部分,来自其中一个原始值。

它也不依赖于使用的符号,只要用作键的字符串不用于其他任何符号。

import re

# this function both returns and mutates
# so that each list only has to be flattened once
def flatten(lst):
    new_lst = []
    for i, item in enumerate(lst):
        if isinstance(item, list):
            new_lst.extend(flatten(item))
        else:
            new_lst.append(item)
    lst[:] = new_lst
    return lst

def flatten_symbols(d):
    # split the values using the keys as delimiters
    delims = re.compile('({})'.format('|'.join(d)))
    d = dict((key, delims.split(value)) for key, value in d.iteritems())
    # turn the value lists into recursive lists
    # replacing each occurence of a key with the corresponding value
    for key, value in d.iteritems():
        for i, item in enumerate(value):
            if item in d:
                d[key][i] = d[item]
    # flatten the recursive lists
    return dict((key, ''.join(flatten(value))) for key, value in d.iteritems())


d={'s1':{'a':'b+c','b':'f+g', 'f': 'd+e', 'e': 'h+i'},'s2':{'a':'b+c','b':'f+g'}}

new_d = dict((key, flatten_symbols(subdict)) for key, subdict in d.iteritems())
print new_d