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

そのコードを関数に入れる必要があります。コメントの行は、置き換えたいものに対してその関数を呼び出し、それを文字列に入れ、結果をdictに割り当てる必要があります。

于 2012-04-16T05:18:41.327 に答える
0

このような反復法の問題は、実行時間がネストの深さと内のアイテムの順序に非常に敏感であるということdictです。この再帰バージョンは、結果の「セグメント」の総数で線形時間で実行されdictます。ここで、セグメントは、元の値の1つから取得された式の各部分です。

また、キーとして使用される文字列が他の目的で使用されない限り、使用される記号に依存しません。

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 に答える
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 に答える