Joh*_*web 8 python parsing dictionary
我有一个包含数千行的生成文件,如下所示:
CODE,XXX,DATE,20101201,TIME,070400,CONDITION_CODES,LTXT,PRICE,999.0000,QUANTITY,100,TSN,1510000001
某些行具有更多字段而其他行具有更少字段,但所有行都遵循相同的键值对模式,并且每行具有TSN字段.
在对文件进行一些分析时,我写了一个像下面这样的循环来将文件读入字典:
#!/usr/bin/env python
from sys import argv
records = {}
for line in open(argv[1]):
fields = line.strip().split(',')
record = dict(zip(fields[::2], fields[1::2]))
records[record['TSN']] = record
print 'Found %d records in the file.' % len(records)
Run Code Online (Sandbox Code Playgroud)
...这很好,完全符合我的要求(这print只是一个简单的例子).
但是,对我来说它并没有感觉特别"pythonic"和以下行:
dict(zip(fields[::2], fields[1::2]))
Run Code Online (Sandbox Code Playgroud)
这只是感觉"笨重"(它在田野上迭代了多少次?).
是否有更好的方法在Python 2.6中使用标准模块进行此操作?
mar*_*eau 19
在Python 2中,您可以izip在itertools模块中使用生成器对象的魔力来编写自己的函数,以简化dict记录的值对的创建.我pairwise()从Python 2 文档中的一个类似命名(但功能不同)的配方中得到了这个想法itertools.
要在Python 3中使用该方法,您可以使用plain,zip()因为它执行izip()Python 2中的操作,导致后者被删除itertools- 下面的示例解决了这个问题,并且应该在两个版本中都有效.
try:
from itertools import izip
except ImportError: # Python 3
izip = zip
def pairwise(iterable):
"s -> (s0,s1), (s2,s3), (s4, s5), ..."
a = iter(iterable)
return izip(a, a)
Run Code Online (Sandbox Code Playgroud)
在文件读取for循环中可以这样使用:
from sys import argv
records = {}
for line in open(argv[1]):
fields = (field.strip() for field in line.split(',')) # generator expr
record = dict(pairwise(fields))
records[record['TSN']] = record
print('Found %d records in the file.' % len(records))
Run Code Online (Sandbox Code Playgroud)
但等等,还有更多!
可以创建一个我将调用的通用版本grouper(),它同样对应于一个类似命名但功能不同的itertools配方(在下面列出pairwise()):
def grouper(n, iterable):
"s -> (s0,s1,...sn-1), (sn,sn+1,...s2n-1), (s2n,s2n+1,...s3n-1), ..."
return izip(*[iter(iterable)]*n)
Run Code Online (Sandbox Code Playgroud)
在你的for循环中可以这样使用:
record = dict(grouper(2, fields))
Run Code Online (Sandbox Code Playgroud)
当然,对于这样的特定情况,它很容易使用functools.partial()并创建一个类似的pairwise()功能(它将在Python 2和3中都有效):
import functools
pairwise = functools.partial(grouper, 2)
Run Code Online (Sandbox Code Playgroud)
后记
除非有非常多的字段,否则您可以在成对的行项目中创建一个实际的序列(而不是使用没有的生成器表达式len()):
fields = tuple(field.strip() for field in line.split(','))
Run Code Online (Sandbox Code Playgroud)
这样做的好处是可以使用简单的切片完成分组:
try:
xrange
except NameError: # Python 3
xrange = range
def grouper(n, sequence):
for i in xrange(0, len(sequence), n):
yield sequence[i:i+n]
pairwise = functools.partial(grouper, 2)
Run Code Online (Sandbox Code Playgroud)
没有那么好,只是效率更高......