2

我有一个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

4 回答 4

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'}它会进入一个无限循环(尽管这听起来不应该从你的评论中发生)。

于 2012-04-16T05:48:21.733 回答
0

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

于 2012-04-16T05:18:41.327 回答
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'}
于 2012-04-16T05:53:55.250 回答
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
于 2012-04-16T06:07:12.727 回答