2014-12-19 95 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']={} 

我是新来的蟒蛇那么谁能帮助我通过这个

+0

对不起。我是python的新手,但是这个输出的解决方案是什么。 – sachin27 2014-12-19 08:50:28

+0

是的。对不起。 – sachin27 2014-12-19 08:52:03

+0

如果每行的最后一部分不是“:pass”,该怎么办? – martineau 2014-12-19 08:52:55

回答

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结束。

扩展abc.txt测试文件:

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

输出:

​​

请让我知道,如果这是你对每行计算的最后一个字评论的正确解释。

+0

谢谢。有用 。 – sachin27 2014-12-19 23:26:31

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 2014-12-19 06:00:57

+0

是否可以动态添加密钥而不是硬编码。 – sachin27 2014-12-19 06:22:06

+0

@ sachin27:硬编码的键可以用'p.findall()'中的变量或值替换。 – martineau 2014-12-19 16:55:56

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}}}}}