Python 在多个标题行上拆分csv中的行
我对python很陌生,所以请温柔一点 我有一个.csv文件,以这种格式向我报告,因此我对此无能为力:Python 在多个标题行上拆分csv中的行,python,csv,dictionary,Python,Csv,Dictionary,我对python很陌生,所以请温柔一点 我有一个.csv文件,以这种格式向我报告,因此我对此无能为力: ClientAccountID AccountAlias CurrencyPrimary FromDate SomeID SomeAlias SomeCurr SomeDate OtherID OtherAlias OtherCurr OtherDate ClientAccountID
ClientAccountID AccountAlias CurrencyPrimary FromDate
SomeID SomeAlias SomeCurr SomeDate
OtherID OtherAlias OtherCurr OtherDate
ClientAccountID AccountAlias CurrencyPrimary AssetClass
SomeID SomeAlias SomeCurr SomeClass
OtherID OtherAlias OtherCurr OtherDate
AnotherID AnotherAlias AnotherCurr AnotherDate
我正在使用python中的csv包,因此我有:
with open(theFile, 'rb') as csvfile:
theReader = csv.DictReader(csvfile, delimiter = ',')
据我所知,它创造了字典“theReader”。如何将此词典子集为多个词典,并按原始csv文件中的标题行进行拆分?是否有一种简单、优雅、非循环的方法来创建字典列表(甚至是一个字典字典,使用帐户ID作为键)?这有意义吗
哦。请注意,标题行并不相等,但标题行将始终以“ClientAccounted”开头
多亏了@codie,我现在基于使用“\t”分隔符,使用以下命令将csv拆分为几个dict
with open(theFile, 'rb') as csvfile:
theReader = csv.DictReader(csvfile, delimiter = '\t')
但是,我现在将整个标题行作为键,将其他行作为值。我该如何进一步拆分
感谢下面的@Benjamin Hodgson,我有以下几点:
from csv import DictReader
from io import BytesIO
stringios = []
with open('file.csv', 'r') as f:
stringio = None
for line in f:
if line.startswith('ClientAccountID'):
if stringio is not None:
stringios.append(stringio)
stringio = BytesIO()
stringio.write(line)
stringio.write("\n")
stringios.append(stringio)
data = [list(DictReader(x.getvalue(), delimiter=',')) for x in stringios]
如果我在stringios中打印第一个项目,我会得到预期的结果。它看起来像一个单一的csv。但是,如果我使用下面的方法打印数据中的第一项,我会得到一些奇怪的结果:
for row in data[0]:
print row
它返回:
{'C':'U'}
{'C':'S'}
{'C':'D'}
...
因此,它似乎在拆分每个字符,而不是使用逗号分隔符。如果我正确理解了您的问题,您有一个包含多个表的CSV文件。表格由标题行分隔,标题行始终以字符串
“clientaccounted”
开头
因此,任务是将CSV文件读入字典列表。列表中的每个条目都对应于CSV文件中的一个表
我是这样做的:
“clientAccount”
开头的行来执行此操作DictReader
将这些文件读入词典列表StringIO
是内存中的文件。它通过将字符串包装到类似文件的接口来工作)
如果遇到以'ClientAccountID'
开头的行,我们将当前的StringIO
放入列表,并开始写入新的行。完成后,记得将最后一个也添加到列表中。
在使用StringIO.seek(0)
写入StringIO后,不要忘记(正如我在本答案的早期版本中所做的那样)回放StringIO
现在可以直接循环StringIO
s以获得字典表
data = [list(DictReader(x, delimiter='\t')) for x in stringios]
对于列表stringios
中的每个类似文件的对象,创建一个DictReader
并将其读入列表
如果您的数据太大,无法放入内存,那么修改这种方法并不难。使用生成器而不是列表,并逐行处理。如果数据不是逗号或制表符分隔的,则可以使用str.split
,您可以将其与itertools.groupby
组合以分隔标题和行:
from itertools import groupby, izip, imap
with open("test.txt") as f:
grps, data = groupby(imap(str.split, f), lambda x: x[0] == "ClientAccountID"), []
for k, v in grps:
if k:
names = next(v)
vals = izip(*next(grps)[1])
data.append(dict(izip(names, vals)))
from pprint import pprint as pp
pp(data)
输出:
[{'AccountAlias': ('SomeAlias', 'OtherAlias'),
'ClientAccountID': ('SomeID', 'OtherID'),
'CurrencyPrimary': ('SomeCurr', 'OtherCurr'),
'FromDate': ('SomeDate', 'OtherDate')},
{'AccountAlias': ('SomeAlias', 'OtherAlias', 'AnotherAlias'),
'AssetClass': ('SomeClass', 'OtherDate', 'AnotherDate'),
'ClientAccountID': ('SomeID', 'OtherID', 'AnotherID'),
'CurrencyPrimary': ('SomeCurr', 'OtherCurr', 'AnotherCurr')}]
如果以制表符分隔,只需更改一行:
with open("test.txt") as f:
grps, data = groupby(csv.reader(f, delimiter="\t"), lambda x: x[0] == "ClientAccountID"), []
for k, v in grps:
if k:
names = next(v)
vals = izip(*next(grps)[1])
data.append(dict(izip(names, vals)))
使用制表符分隔符,(\t)
而不是逗号分隔符。多简单啊。然后如何创建子字典?用于reader:do something()中的行,其中行是给定行中的值的dict。Python为您提供了所有隐藏的魔力。您需要展示csv文件中的一些实际行,以便我们能够给您一个正确的答案。如果您有一个csv文件,其中有三行(或七行)的块中有多个不同的id,那么在读取该文件时,您需要做一些魔术。目前的例子是模棱两可的…您需要编造一些虚假数据,以便更好地了解格式。取前10行或其他内容并混淆数据。我得到一个错误:stringio.write(line)TypeError:unicode参数应为'str',是的,您完全理解我的意图。谢谢。这个答案是Python 3代码。根据那个错误信息,我猜你是在2.7上。尝试将StringIO
更改为BytesIO
。是的,我使用的是2.7。这些信息可能与。。。道歉。仍然会遇到问题,因为它似乎在工作,但“数据”在完成时是空的。我正在处理它。建议没有任何以'clientaccount'
开头的行。行的开头有空格吗?如果是这样,请尝试line.strip().startswith('ClientAccountID')
而不是line.startswith(…)
。(另外,我刚刚发现并修复了答案中的一个bug;)抱歉-刚刚更新。似乎无法识别分隔符?或者是在每个字符处拆分,而不是在逗号处。这很好。我不知道lambda这个东西,但它非常有用。另外,你能不能在第二秒也使用str.split?是否有方法向其传递不同的分隔符(\t)?另外,查看imap的文档,它表示imap(函数,*iterables),这意味着文件f是可写的?我是python新手,我只是好奇,但是当传递一个文件时,它会被解释为一组iterable行吗?如果是这样,您迭代这些行,str.split它们,然后按第一个术语是clientAccounted的行对它们进行分组?我想我理解对了,但似乎。。。不寻常(?)文件只是一组可编辑的行?或者这(相当)正常?谢谢你@lukehawk,您可以传递任何您想要的分隔符,但是在map示例中,您需要使用map(lambda x:x.split(“whatever”)
,我们可以传递str.split
,因为它是可调用的,所以我们不需要lambda,是的,一个文件对象返回它自己的迭代器,这样当你迭代它时,你每次都会得到一行,imap在任何空格上拆分每一行,然后每次我们如果k
为真,我们就有一行带有f
with open("test.txt") as f:
grps, data = groupby(csv.reader(f, delimiter="\t"), lambda x: x[0] == "ClientAccountID"), []
for k, v in grps:
if k:
names = next(v)
vals = izip(*next(grps)[1])
data.append(dict(izip(names, vals)))