2016-09-20 4 views
3

Я работаю с DeepDiff. Поэтому у меня есть такие результаты:Parsing DeepDiff результат

local = [{1: {'age': 50, 'name': 'foo'}}, {2: {'age': 90, 'name': 'bar'}}, {3: {'age': 60, 'name': 'foobar'}}] 
online = [{1: {'age': 50, 'name': 'foo'}}, {2: {'age': 40, 'name': 'bar'}}] 
ddiff = DeepDiff(local, online) 
added, updated = ddiff['iterable_item_added'], ddiff['values_changed'] 
added = {'root[2]': {3: {'age': 60, 'name': 'foobar'}}} 
updated = {"root[1][2]['age']": {'new_value': 90, 'old_value': 40}} 

Теперь, я хочу взять:

list_indexes_added = foo(added) 
list_indexes_updated = foo(updated) 

и получить:

list_indexes_added = [2] 
list_index_updated = [(1,2,'age')] 

таким образом, я могу управлять списком local и online и в будущем обновить таблицу online.

Я думаю в регулярных выражениях, но, возможно, есть другой вариант.

ответ

2
  • Одним из решений может быть регулярное выражение и пользовательский разбор матчей.

  • Другой может использовать literal_eval после регулярных выражений разбора этих строк, если выходной формат deepdiff соответствует

    from ast import literal_eval 
    import re 
    
    
    def str_diff_parse(str_diff): 
        return [tuple(literal_eval(y) for y in re.findall(r"\[('?\w+'?)\]", x)) for x in str_diff] 
    
    added = {'root[2]': {3: {'age': 60, 'name': 'foobar'}}} 
    updated = {"root[1][2]['age']": {'new_value': 90, 'old_value': 40}} 
    
    list_indexes_added = str_diff_parse(added) 
    list_indexes_updated = str_diff_parse(updated) 
    
    print(list_indexes_added) 
    print(list_indexes_updated) 
    # prints 
    #[(2,)] 
    #[(1, 2, 'age')] 
    

демо: http://ideone.com/3MhTky

  • также Рекомендовал бы dictdiffer модуль, он возвращает diff в качестве расходуемого объекта diff python, который может быть исправлены в оригинальном словаре, чтобы получить обновленный или наоборот.
1

Итак, я бы что-то вроде этого:

import re 

def foo(diff): 
modded = [] 

for key in diff.keys(): 
    m = re.search('\[(.+)\]', key) 
    modded.append(tuple(m.group(1).split(']['))) 

return modded 

Он будет читать каждый ключ, извлечь только индексы (будь то цифровой или строка), затем нарезать строку. Так как ваш желаемый результат указывает кортеж, он вернет последовательность индексов назад, а затем вернет весь список наборов индексов (так как diff может иметь более одного).

Это может быть golfed вниз в одну строку списка осмыслению:

import re 

def foo(diff): 
    return [tuple(re.search('\[(.+)\]', key).group(1).split('][')) for key in diff.keys()] 
1

Это то, что я сделал:

def getFromSquareBrackets(s): 
    return re.findall(r"\['?([A-Za-z0-9_]+)'?\]", s) 

def auxparse(e): 
    try: 
     e = int(e) 
    except: 
     pass 
    return e 

def castInts(l): 
    return list((map(auxparse, l))) 

def parseRoots(dics): 
    """ 
     Returns pos id for list. 
     Because we have formmatted [{id:{dic}}, {id:{dic}}] 
    """ 
    values = [] 
    for d in dics: 
     values.append(castInts(getFromSquareBrackets(d))) 
    return values 

Итак:

parseRoots({"root[1][2]['age']": {'new_value': 90, 'old_value': 40}}) 
[[1, 2, 'age']] 

Может быть кто-то может улучшить его.