Python - 嵌套字典。这个bug在哪里?

时间:2015-03-13 14:45:43

标签: python csv dictionary nested

我有一个CSV文件,我已将其过滤到列表中并进行分组。例如:

     52713
     ['52713', '', 'Vmax', '', 'Start Value', '', '\n']
     ['52713', '', 'Vmax', '', 'ECNumber', '1.14.12.17', '\n']
     ['52713', 'O2', 'Km', 'M', 'Start Value', '3.5E-5', '\n']
     ['52713', 'O2', 'Km', 'M', 'ECNumber', '1.14.12.17', '\n']
     52714
     ['52714', '', 'Vmax', '', 'Start Value', '', '\n']
     ['52714', '', 'Vmax', '', 'ECNumber', '1.14.12.17', '\n']
     ['52714', 'O2', 'Km', 'M', 'Start Value', '1.3E-5', '\n']
     ['52714', 'O2', 'Km', 'M', 'ECNumber', '1.14.12.17', '\n']

由此,我创建了一个嵌套字典,其结构为:

   dict = ID number:{Km:n, Kcat:n, ECNumber:n}

...列表中的每个ID。

我使用以下代码创建此词典

    dict = {}

    for key, items in groupby(FilteredTable1[1:], itemgetter(0)):
        #print key
        for subitem in items:
            #print subitem
            dict[subitem[EntryID]] = {}
            dict[subitem[EntryID]]['EC'] = []
            dict[subitem[EntryID]]['Km'] = []
            dict[subitem[EntryID]]['Kcat'] = []
            if 'ECNumber' in subitem:
                dict[subitem[EntryID]]['EC'] = subitem[value]

            if 'Km' in subitem and 'Start Value' in subitem:
                dict[subitem[EntryID]]['Km'] = subitem[value]
                #print subitem

这适用于ECNumber值,但不适用于Km值。它可以打印该行,表明它将Km值标识为存在,但不会将其放入字典中。

示例输出:

    {'Km': [], 'EC': '1.14.12.17', 'Kcat': []}

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

问题是你的内部for循环会重新初始化dict[subitem[EntryID]],即使它已经存在。通过明确检查以确定它是否已存在,以下内容已得到修复:

dict = {}

for key, items in groupby(FilteredTable1[1:], itemgetter(0)):
    #print key
    for subitem in items:
        #print ' ', subitem
        if subitem[EntryID] not in dict:
            dict[subitem[EntryID]] = {}
            dict[subitem[EntryID]]['EC'] = []
            dict[subitem[EntryID]]['Km'] = []
            dict[subitem[EntryID]]['Kcat'] = []

        if 'ECNumber' in subitem:
            dict[subitem[EntryID]]['EC'] = subitem[value]

        if 'Km' in subitem and 'Start Value' in subitem:
            dict[subitem[EntryID]]['Km'] = subitem[value]
            #print subitem

但是,通过使用类似以下内容的方式可以提高此代码的效率,从而避免重新计算值和双字典查找。它也不使用内置类型的名称作为变量名称,这违反了PEP8 - Style Guide for Python Code中给出的指导原则。它还建议仅将CamelCase用于类名,而不是像FilteredTable1那样使用变量名称 - 但我没有改变它。

adict = {}

for key, items in groupby(FilteredTable1[1:], itemgetter(0)):
    #print key
    for subitem in items:
        #print ' ', subitem
        entry_id = subitem[EntryID]
        if entry_id not in adict:
            adict[entry_id] = {'EC': [], 'Km': [], 'Kcat': []}

        entry = adict[entry_id]
        if 'ECNumber' in subitem:
            entry['EC'] = subitem[value]

        if 'Km' in subitem and 'Start Value' in subitem:
            entry['Km'] = subitem[value]
            #print subitem

实际上,由于您正在构建字典词典,因此使用groupby这样做是不明白的。

答案 1 :(得分:1)

我发布此内容以跟进并延伸到我的previous answer

对于初学者来说,您可以进一步简化代码,无需检查预先存在的条目,只需将字典创建为collections.defaultdict dict子类而不是常规字段:

from collections import defaultdict
adict = defaultdict(lambda: {'EC': [], 'Km': [], 'Kcat': []})

for key, items in groupby(FilteredTable1[1:], itemgetter(0)):
    for subitem in items:
        entry = adict[subitem[EntryID]]
        if 'ECNumber' in subitem:
            entry['EC'] = subitem[value]

        if 'Km' in subitem and 'Start Value' in subitem:
            entry['Km'] = subitem[value]

其次,正如我在另一个答案中所提到的,我不认为你通过使用itertools.groupby()来做任何事情 - 除了使过程比需要更复杂。这是因为基本上你正在做的是制作一个字典词典,其条目都可以随机访问,所以在这样做之前解决它们的麻烦没有任何好处。下面的代码证明了这一点(结合使用defaultdict,如上所示):

adict = defaultdict(lambda: {'EC': [], 'Km': [], 'Kcat': []})

for subitem in FilteredTable1[1:]:
    entry = adict[subitem[EntryID]]
    if 'ECNumber' in subitem:
        entry['EC'] = subitem[value]

    if 'Km' in subitem and 'Start Value' in subitem:
        entry['Km'] = subitem[value]