2016-10-14 3 views
3

Цель, которую я хочу достичь, - обменять все предметы, чья форма #item_name# от (item_value) в dict. Я использую два dict с именем test1 и test2 для проверки моей функции. Вот код:Как сделать замену в python's dict?

test1={'integer_set': '{#integer_list#?}', 'integer_list': '#integer_range#(?,#integer_range#)*', 'integer_range': '#integer#(..#integer#)?', 'integer': '[+-]?\\d+'} 
test2={'b': '#a#', 'f': '#e#', 'c': '#b#', 'e': '#d#', 'd': '#c#', 'g': '#f#', 'a': 'correct'} 
def change(pat_dict:{str:str}): 
    print('Expanding: ',pat_dict) 
    num=0 
    while num<len(pat_dict): 
     inv_pat_dict = {v: k for k, v in pat_dict.items()} 
     for value in pat_dict.values(): 
      for key in pat_dict.keys(): 
       if key in value: 
        repl='#'+key+'#' 
        repl2='('+pat_dict[key]+')' 
        value0=value.replace(repl,repl2) 
        pat_dict[inv_pat_dict[value]]=value0 
     num+=1 
    print('Result: ',pat_dict)  

change(test1) 
change(test2) 

иногда я могу получить правильный результат, как:

Expanding: {'integer': '[+-]?\\d+', 'integer_list': '#integer_range#(?,#integer_range#)*', 'integer_set': '{#integer_list#?}', 'integer_range': '#integer#(..#integer#)?'} 
Result: {'integer': '[+-]?\\d+', 'integer_list': '(([+-]?\\d+)(..([+-]?\\d+))?)(?,(([+-]?\\d+)(..([+-]?\\d+))?))*', 'integer_set': '{((([+-]?\\d+)(..([+-]?\\d+))?)(?,(([+-]?\\d+)(..([+-]?\\d+))?))*)?}', 'integer_range': '([+-]?\\d+)(..([+-]?\\d+))?'} 
Expanding: {'c': '#b#', 'f': '#e#', 'e': '#d#', 'b': '#a#', 'g': '#f#', 'd': '#c#', 'a': 'correct'} 
Result: {'c': '((correct))', 'f': '(((((correct)))))', 'e': '((((correct))))', 'b': '(correct)', 'g': '((((((correct))))))', 'd': '(((correct)))', 'a': 'correct'} 

Но большую часть времени я получаю неправильные результаты как то:

Expanding: {'integer_range': '#integer#(..#integer#)?', 'integer': '[+-]?\\d+', 'integer_set': '{#integer_list#?}', 'integer_list': '#integer_range#(?,#integer_range#)*'} 
Result: {'integer_range': '([+-]?\\d+)(..([+-]?\\d+))?', 'integer': '[+-]?\\d+', 'integer_set': '{(#integer_range#(?,#integer_range#)*)?}', 'integer_list': '#integer_range#(?,#integer_range#)*'} 
Expanding: {'f': '#e#', 'a': 'correct', 'd': '#c#', 'g': '#f#', 'b': '#a#', 'c': '#b#', 'e': '#d#'} 
Result: {'f': '(((((correct)))))', 'a': 'correct', 'd': '(((correct)))', 'g': '((((((correct))))))', 'b': '(correct)', 'c': '((correct))', 'e': '((((correct))))'} 

Как я могу обновить мой код для достижения моей цели?

ответ

0

Ваша проблема вызвана тем, что словари python неупорядочены. Попробуйте использовать OrderedDict вместо dict, и все должно быть в порядке. OrderedDict работает так же, как обычный dict, но с сохранением заказа при небольшой стоимости исполнения.

Обратите внимание, что, хотя вы могли бы создать OrderedDict из литерала dict (как я сделал здесь вначале), этот dict будет неупорядоченным, поэтому заказ может быть не гарантирован. Использование списка пар (key, value) сохраняет порядок во всех случаях.

from collections import OrderedDict 

test1=OrderedDict([('integer_set', '{#integer_list#?}'), ('integer_list', '#integer_range#(?,#integer_range#)*'), ('integer_range', '#integer#(..#integer#)?'), ('integer', '[+-]?\\d+')]) 
test2=OrderedDict([('b', '#a#'), ('f', '#e#'), ('c', '#b#'), ('e', '#d#'), ('d', '#c#'), ('g', '#f#'), ('a', 'correct')]) 
def change(pat_dict:{str:str}): 
    print('Expanding: ',pat_dict) 
    num=0 
    while num<len(pat_dict): 
     inv_pat_dict = {v: k for k, v in pat_dict.items()} 
     for value in pat_dict.values(): 
      for key in pat_dict.keys(): 
       if key in value: 
        repl='#'+key+'#' 
        repl2='('+pat_dict[key]+')' 
        value0=value.replace(repl,repl2) 
        pat_dict[inv_pat_dict[value]]=value0 
     num+=1 
    print('Result: ',pat_dict) 

change(test1) 
change(test2) 
+0

Рандомизация является [для предотвращения веб-сервисов от того, ДОС-е изд] (https://docs.python.org/3/reference/datamodel.html#object.__hash__), когда пользователь может создавать произвольные ключи в 'dict' и может обрабатывать указанные ключи, чтобы вызвать хеш-коллизии, уменьшая большинство операций' dict' от 'O (1)' до 'O (n)'. Тот факт, что он влияет на порядок итерации, на самом деле не является конструкцией _goal_ (и на самом деле, в CPython 3.6, 'dict's, вероятно, будут итерировать в порядке ввода по умолчанию из-за изменения реализации, которое происходит для достижения этого в качестве свободной стороны, эффект изменения на меньшую память голодный 'dict' дизайн). – ShadowRanger

+0

Я стою исправлено. Такое же поведение присутствует в Go, где нужно избегать того, чтобы разработчики доверяли упорядочению вывода 'map'. Ред. То, чего я не понимаю, - это то, почему порядок итераций изменился при каждом чтении без прерывистой записи; как это могло бы избежать столкновения хэшей? @ShadowRanger –

0

Попробуйте этот. Ваша проблема связана с мутацией начала dict. Вам нужно изменить его копию.

test1={'integer_set': '{#integer_list#?}', 'integer_list': '#integer_range#(?,#integer_range#)*', 'integer_range': '#integer#(..#integer#)?', 'integer': '[+-]?\\d+'} 
test2={'b': '#a#', 'f': '#e#', 'c': '#b#', 'e': '#d#', 'd': '#c#', 'g': '#f#', 'a': 'correct'} 
def change(d): 
    new_d = d.copy() 
    for k in d.keys(): 
     for nk, v in new_d.items(): 
      if k in v: 
       new_d[nk] = v.replace('#{}#'.format(k), '({})'.format(new_d[k])) 
    return new_d 

test1 = change(test1) 
test2 = change(test2)