Python:从文件输出中读取值,并将字典解释为键值

时间:2013-10-30 22:24:02

标签: python file-io dictionary key-value-coding

我是字典的新手,在理解如何将文件的输出解释为字典并读取它的键值对方面遇到了麻烦。

这是我的脚本,它将文件的输出作为字典:

dicts = {}
for line in sys.stdin:
   d = ast.literal_eval(line)
   for k,v in d.items():
      dicts.setdefault(k, []).append(v)
      charcount = sum(int(d['charcount']) for d in dicts[k])
      output_dict = {k: {'charcount': charcount}}
      print output_dict

以下是我的文件的输出,脚本将其作为输入:

{ 262968617233162240 : {'@': False, '#': False, 'word': 'good#1st#time#will',    'longword': True, 'title': False, 'charcount': 18, 'uppercase': False, 'stop': False, 'sscore': False, 'url': False, '!!!': False} }
{ 262968617233162240 : {'@': False, '#': False, 'word': 'be', 'longword': False, 'title': False, 'charcount': 2, 'uppercase': False, 'stop': True, 'sscore': False, 'url': False, '!!!': False} }
{ 262968617233162240 : {'@': False, '#': False, 'word': 'going', 'longword': False, 'title': False, 'charcount': 5, 'uppercase': False, 'stop': False, 'sscore': False, 'url': False, '!!!': False} }
{ 262968617233162240 : {'@': False, '#': False, 'word': 'back#', 'longword': False, 'title': False, 'charcount': 5, 'uppercase': False, 'stop': False, 'sscore': False, 'url': False, '!!!': False} }
{ 263790847424880641 : {'@': False, '#': False, 'word': 'http://instagr.am/p/rx9939civ8/\xc2\xa0', 'longword': True, 'title': False, 'charcount': 33, 'uppercase': False, 'stop': False, 'sscore': False, 'url': True, '!!!': False} }

当我运行脚本时,我得到重复的值而不是解析整个输入。

感谢。

2 个答案:

答案 0 :(得分:1)

我怀疑你在实际寻找的东西不是一个大字典,而是一个字典列表,每行一个。例如:

dicts = []
for line in sys.stdin:
    dicts.append(eval(line))

我实际上会用ast.literal_eval(如eval)文档建议的那样写这个,*并将其简化为列表理解:

dicts = [ast.literal_eval(line) for line in sys.stdin]

但不管怎样,现在dicts中的每个元素都是一个字典。所以,打印出来:

for d in dicts:
    print d

唯一的是,你想对它们进行排序。我不确定你想要对它们进行排序 。一般来说,排序字典没有任何意义(这就是为什么Python 2给你一个无意义的顺序,Python 3给你一个TypeError)。当然,特殊情况下有一些有意义的顺序,但每种情况都不同。

也许在你的情况下,你想依赖每个字典都有一个密钥的事实,并对该密钥进行排序?如果是这样的话:

for d in sorted(dicts, key=lambda d: d.keys()[0]):
    print d

但这只是猜测。


来自评论:

  

如何使用相同的键对所有词典中的charcount(它存在于dict的值部分中)进行计数。

如果你想这样做,你有两种选择。

首先,您可以随时搜索整个词典列表,如下所示:

charcounts = []
for d in dicts:
    for k, v in d.items():
        if k == key:
            charcounts.append(v['charcount'])

但在这种情况下,使用“multidict”结构可能会更好 - 也就是说,dict的值都是列表(在这种情况下是dicts)。

有两种简单的方法可以构建多字词 - setdefault上的dict方法或defaultdict中的collections类。两者都同样简单;不同的是,第一个给你一个常规的dict,所以它是一个KeyError来寻找一个不存在的密钥,而第二个给你一个defaultdict,所以你会得到一个空列表,寻找一个不存在的密钥。我会展示第一个,但实际上,你必须决定你想要哪一个。

dicts = {}
for line in sys.stdin:
    d = ast.literal_eval(line)
    for k, v in d.items(): # should only be one
        dicts.setdefault(k, []).append(v)

这需要设置一些工作,但搜索工作量较少。例如,上面的整个混乱可以用一行代替:

charcounts = [d['charcount'] for d in dicts[key]]

...而且,如果dicts非常大,它会快得多,因为它只需要查看具有匹配键的键,而不是所有键。

为了让您了解这是什么样子,这里有dicts您的样本输入:

{262968617233162240: 
    [
        {'!!!': False, '#': False, '@': False, 'charcount': 18, 'longword': True, 'sscore': False, 'stop': False, 'title': False, 'uppercase': False, 'url': False, 'word': 'good#1st#time#will'},
        {'!!!': False, '#': False, '@': False, 'charcount': 2, 'longword': False, 'sscore': False, 'stop': True, 'title': False, 'uppercase': False, 'url': False, 'word': 'be'},
        {'!!!': False, '#': False, '@': False, 'charcount': 5, 'longword': False, 'sscore': False, 'stop': False, 'title': False, 'uppercase': False, 'url': False, 'word': 'going'},
        {'!!!': False, '#': False, '@': False, 'charcount': 5, 'longword': False, 'sscore': False, 'stop': False, 'title': False, 'uppercase': False, 'url': False, 'word': 'back#'}
    ],
 263790847424880641: 
    [
        {'!!!': False, '#': False, '@': False, 'charcount': 33, 'longword': True, 'sscore': False, 'stop': False, 'title': False, 'uppercase': False, 'url': True, 'word': 'http://instagr.am/p/rx9939civ8/\xc2\xa0'}
    ]
}

来自另一条评论:

  

所以我要找的输出是:{262968617233162240,charcount:30}

嗯,这不是Python中的有效内容。它看起来像集合和字典之间的某个东西。 dict是一组键值对,每个键和值之间都有一个冒号。

以下是 在Python中有效的内容:

{262968617233162240: {'charcount': 30}}

你会怎么做到的?

好吧,我已经向您展示了如何获取任何给定键的charcounts列表。在添加它们之前,您必须将它们全部转换为数字:

charcounts = [int(d['charcount']) for d in dicts[key]]

然后,要添加它们,只需致电sum

charcount = sum(int(d['charcount']) for d in dicts[key])

现在,我们如何构建您想要的输出?

charcount = sum(int(d['charcount']) for d in dicts[key])
output_dict = {key: {'charcount': charcount}}

如果你想对multidict中的每个键执行此操作:

for key, values in dicts.items():
    charcount = sum(int(d['charcount']) for d in values)
    output_dict = {key: {'charcount': charcount}}
    # now do something with output_dict

*或者,更好的是,更改保存代码以使用实际用于数据交换的格式,例如JSONpickle

答案 1 :(得分:0)

您有两个主要问题:

1)

print dicts[v]

无法工作,因为使用键调用dict,v是值。 这个电话应该给你(你的价值实际上是双语):

TypeError: unhashable type: 'dict'

将其更改为

print dicts[k]

并且程序将运行

2)

文件中的三个第一行具有相同的键。所以当你更新字典时它们会被覆盖。所以最后你只有两个输出(四行,因为它包括两个打印调用):

{'@': False, 'uppercase': False, 'stop': False, '!!!': False, '#': False, 'word': 'back#', 'longword': False, 'title': False, 'url': False, 'sscore': False, 'charcount': 5}
262968617233162240 {'@': False, 'uppercase': False, 'stop': False, '!!!': False, '#': False, 'word': 'back#', 'longword': False, 'title': False, 'url': False, 'sscore': False, 'charcount': 5}
{'@': False, 'uppercase': False, 'stop': False, '!!!': False, '#': False, 'word': 'http://instagr.am/p/rx9939civ8/\xc2\xa0', 'longword': True, 'title': False, 'url': True, 'sscore': False, 'charcount': 33}
263790847424880641 {'@': False, 'uppercase': False, 'stop': False, '!!!': False, '#': False, 'word': 'http://instagr.am/p/rx9939civ8/\xc2\xa0', 'longword': True, 'title': False, 'url': True, 'sscore': False, 'charcount': 33}
Script terminated.