【问题标题】:Check key, value of nested dictionary in python?检查python中嵌套字典的键,值?
【发布时间】:2016-11-14 04:47:36
【问题描述】:

我正在我的程序中生成一个嵌套字典。生成后,我想遍历该字典,并检查字典键和值。

程序代码

这是我要迭代的字典,其值包含另一个字典。

 main_dict = {101: {1234: [11111,11111],5678: [44444,44444]},
              102: {9100: [55555,55555],1112: [77777,88888]}}

我正在读取一个 csv 文件并将内容存储在这本字典中。像这样:

Input.csv -

 lineno,item,total
 101,1234,11111
 101,1234,11111
 101,5678,44444
 101,5678,44444
 102,9100,55555
 102,9100,55555
 102,1112,77777
 102,1112,88888

这是输入的 csv 文件。我正在阅读这个 csv 文件,我想知道一个独特的项目总共重复了多少次?

对于我正在做的那些事情:

for line in reader:
                if line[0] in main_dict:
                    if line[1] in main_dict[line[0]]:
                        main_dict[line[0]][line[1]].append(line[2])
                    else:
                        main_dict[line[0]].update({line[1]:[line[2]]})
                else:
                    main_dict[line[0]] = {line[1]:[line[2]]}

print main_dict

上述程序的输出:

 {101: {1234: [11111,11111],5678: [44444,44444]},
  102: {9100: [55555,55555],1112: [77777,88888]}}

但我在这一行遇到以下错误-

 if line[1] in main_dict[line[0]]:
 IndexError: list index out of range

ma​​in_dict的迭代-

 for key,value in main_dict.iteritems():
            f1 = open(outputfile + op_directory +'/'+ key+'.csv', 'w')
            writer1 = csv.DictWriter(f1, delimiter=',', fieldnames = fieldname)
            writer1.writeheader()
            if type(value) == type({}):
                for k,v in value.iteritems():
                    if type(v) == type([]):
                        set1 = set(v)
                        for se in set1:
                           writer1.writerow({'item':k,'total':se,'total_count':v.count(se)})

我想知道迭代此类字典的最佳方法?

有时我会得到正确的结果,就像上面的字典一样,但很多时候我都会遇到这个错误,我错过了什么?

提前致谢!

【问题讨论】:

  • 您缺少检查 main_dict[line[0]] 是否存在 - if not main_dict[line[0]]: #do whatever you find right to
  • 可能其中一行缺少信息。好像不完整。
  • 你能给我们一个失败的输入 csv 吗?我怀疑你在某处有一个空行。
  • @dmitryro- 仅在 for 循环之后,我正在检查 main_dict 中是否存在 line[0],如果不存在,则添加整行。
  • @Dean Fenster- 不是空行问题。我添加了 if line: then only operation get perform

标签: python dictionary


【解决方案1】:

正如 cmets 所指出的,您没有检查 line 的长度是否为 3:

for line in reader:
    if not len(line) == 3:
        continue

关于你的算法,我会使用嵌套的defaultdict 来避免 if/else 行。

编辑:我在问题编辑后添加了一个新的 defaultdict 和 csv 写作部分:

from collections import defaultdict
import csv

counter = defaultdict(lambda: defaultdict(list))
main_dict= defaultdict(lambda: defaultdict(lambda: defaultdict(dict)))
fieldnames=['item', 'total', 'total_count']

# we suppose reader is a cvs.reader object
with open('input.csv', 'rb') as csvfile:
    reader = csv.reader(csvfile, delimiter=',')
    for line in reader:
        if not len(line) == 3:
            continue
        # Remove unwanted spaces
        lineno, item, total = [el.strip() for el in line]
        # Do not deal with non digit entries (title for example)
        if not lineno.isdigit():
            continue
        counter[lineno][item].append(total)
        csvdict = {'item': item,
                   'total': total,
                   'total_count': counter[lineno][item].count(total)}
        main_dict[lineno][item][total].update(csvdict)

# The writing part
for lineno in sorted(main_dict):
    itemdict = main_dict[lineno]
    output = 'output_%s.csv' % lineno
    with open(output, 'wb') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames, delimiter=',')
        writer.writeheader()
        for totaldict in itemdict.values():
            for csvdict in totaldict.values():
                writer.writerow(csvdict)

然后您可以使用以下函数打印结果的可读表示:

def myprint(obj, ntab=0):
    if isinstance(obj, (dict, defaultdict)):
        for k in sorted(obj):
            myprint('%s%s'%(ntab*' ', k), ntab+1)
            myprint(obj[k], ntab+1)
    else:
        print('%s%s'%(ntab*' ', obj))
myprint(main_dict)

但是如果你想计算项目总数,我会使用另一个 defaultdict,以总数作为键,元组 (lineno, item) 作为值:

from collections import defaultdict
import csv

total_dict = defaultdict(list)

# we suppose reader is a cvs.reader object
with open('input.csv', 'rb') as csvfile:
    reader = csv.reader(csvfile, delimiter=',')
    for line in reader:
        if not len(line) == 3:
            continue
        # Remove unwanted spaces
        lineno, item, total = [el.strip() for el in line]
        # Do not deal with non digit entries (title for example)
        if not lineno.isdigit():
            continue
        total_dict[total].append((lineno, item))

你可以很容易地得到每个总数的数量:

>>> print len(total_dict['55555'])
2

【讨论】:

  • @Frodon- 我不希望 total 作为键。我希望 lineno 作为字典的键,它的值包含另一个字典,其键是 item,值是 total。
  • @kit 好的,那么我猜我的第一个建议适合你的需要
  • @Frodon- 是的,但是在第一次迭代时这行 main_dict[lineno][item].append(total) 给出错误,只是因为第一个 lineno 不存在这个 main_dict。
  • @kit 如果 main_dict 是 defaultdict 的一个实例,你不应该得到错误(这是使用 defaultdict 的重点)。除非输入的 csv 文件与您在问题中写的不同。
  • @Frodon- 是的,明白了......我的错误兄弟......但它在这个 main_dict 的迭代中遇到了问题。我正在编辑原始问题并将我的 main_dict 迭代。我想通过阅读这个 main_dict 来编写不同的文件。
猜你喜欢
  • 1970-01-01
  • 2020-10-01
  • 2013-09-05
  • 1970-01-01
  • 2020-05-14
  • 2014-03-30
  • 2022-07-05
  • 2021-02-28
  • 2013-09-20
相关资源
最近更新 更多