2014-12-19 4 views
1

Я имею в файле abc.txtсоздания динамического вложенного словаря

abc/pqr/lmn/xyz:pass 
abc/pqr/lmn/bcd:pass 

мне нужно разобрать эти заявления, и вывод должен быть в гнездовой словаре ниже

{'abc':{'pqr':{'lmn':{'xyz':{'pass':1},{'bcd':{'pass':1}}}}}} 

где 1 является подсчет частот , я могу в состоянии сделать так много, как это

import re 
d={} 
p=re.compile('[a-zA-z]+') 
for line in open('abc.txt'): 
    for key in p.findall(line): 
     d['key']={} 

Я новичок в Python, так может кто-нибудь помочь мне через этот

+0

извините. Я новичок в python, но каково будет решение для этого вывода. – sachin27

+0

есть. простите за это. – sachin27

+0

Что делать, если последняя часть каждой строки не является «: pass»? – martineau

ответ

3

Вот обновленная версия моего ответа, в котором листья древовидная структура данных теперь отличается f в том числе и в остальном. Вместо того, чтобы дерево было строго dict -of-nested-dict s, «листья» на каждой ветви теперь являются экземплярами другого подкласса dict с именем collections.Counter, которые полезны для подсчета количества раз, когда происходит каждый из их ключей. Я сделал это из-за вашего ответа на мой вопрос о том, что должно произойти, если последняя часть каждой строки была чем-то отличным от ":pass" (что было «мы должны положить новый счет для этого ключа»).

Вложенных словари часто называют Tree структур данных и могут быть определены рекурсивно — корень словарь, как ветвь. Ниже используется подкласс dict вместо простого dict, потому что он упрощает их создание, так как вам не требуется специальный случай создания первой ветви следующего уровня вниз (за исключением того, что я все еще делаю, добавляя «листья», потому что они другой подкласс, collections.Counter).

from collections import Counter 
import re 

# (optional) trick that redefines Counter subclass to print like a regular dict 
class Counter(Counter): 
    def __repr__(self): 
     return dict(self).__repr__() 

# borrowed from answer @ http://stackoverflow.com/a/19829714/355230 
class Tree(dict): 
    def __missing__(self, key): 
     value = self[key] = type(self)() 
     return value 

# some functions based on answer @ http://stackoverflow.com/a/14692747/355230 
def nested_dict_get(nested_dict, keys): 
    return reduce(lambda d, k: d[k], keys, nested_dict) 

def nested_dict_set(nested_dict, keys, value): 
    nested_dict_get(nested_dict, keys[:-1])[keys[-1]] = value 

def nested_dict_update_count(nested_dict, keys): 
    if nested_dict_get(nested_dict, keys[:-1]): # update existing Counter 
     nested_dict_get(nested_dict, keys[:-1]).update([keys[-1]]) 
    else:          # create a new Counter 
     nested_dict_set(nested_dict, keys[:-1], Counter([keys[-1]])) 

d = Tree() 
pat = re.compile(r'[a-zA-z]+') 
with open('abc.txt') as file: 
    for line in file: 
     nested_dict_update_count(d, [w for w in pat.findall(line.rstrip())]) 

print d # prints like a regular dict 

Для проверки возможности листа подсчета пересмотренного кода, я использовал следующий файл тест, который включает в себя ту же линию дважды, один раз заканчивается снова :pass и еще заканчивающийся в :fail.

Expanded abc.txt тестовый файл:

abc/pqr/lmn/xyz:pass 
abc/pqr/lmn/bcd:pass 
abc/pqr/lmn/xyz:fail 
abc/pqr/lmn/xyz:pass 

Выход:

{'abc': {'pqr': {'lmn': {'bcd': {'pass': 1}, 'xyz': {'fail': 1, 'pass': 2}}}}} 

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

+0

Спасибо. Оно работает . – sachin27

1

ЗАКАНЧИВАТЬ setdefault метода на словарях.

d = {} 
d.setdefault('pqr', {}).setdefault('lmn', {}).setdefault('xyz', {})['pass'] = 1 
d.setdefault('pqr', {}).setdefault('lmn', {}).setdefault('bcd', {})['pass'] = 1 
d 

дает

{'pqr': {'lmn': {'bcd': {'pass': 1}, 'xyz': {'pass': 1}}}} 
+0

проверю. Благодарю. – sachin27

+0

можно динамически добавлять ключи вместо жесткого кодирования. – sachin27

+0

@ sachin27: жестко закодированные ключи могут быть заменены на переменные или значения из вашего 'p.findall()'. – martineau

0

Если я правильно понял ваш вопрос:

sources = ["abc/pqr/lmn/xyz:pass", "abc/pqr/lmn/bcd:pass", "abc/pqr/lmn/xyz:pass"] 


def prepare_source(source): 
    path, value = source.split(':') 
    elements = path.split('/') 
    return elements, value 


def add_key(elements, value): 
    result = dict() 
    if len(elements) > 1: 
     result[elements[0]] = add_key(elements[1:], value) 

    else: 
     result[elements[0]] = {value: 1} 

    return result 


# base merge function get from here: 
# http://stackoverflow.com/questions/7204805/dictionaries-of-dictionaries-merge 
def merge(a, b, path=None): 
    "merges b into a" 
    if path is None: path = [] 
    for key in b: 
     if key in a: 
      if isinstance(a[key], dict) and isinstance(b[key], dict): 
       merge(a[key], b[key], path + [str(key)]) 
      elif isinstance(a[key], int) and isinstance(b[key], int): 
       a[key] += b[key] 
      else: 
       raise Exception('Conflict at %s' % '.'.join(path + [str(key)])) 
     else: 
      a[key] = b[key] 
    return a 


result = dict() 

for source in sources: 
    result = merge(result, add_key(*prepare_source(source))) 

print result 

выход будет:

{'abc': {'pqr': {'lmn': {'bcd': {'pass': 1}, 'xyz': {'pass': 2}}}}} 
Смежные вопросы