我对python很新,所以请保持温柔。
我有一个.csv文件,以这种格式向我报告,所以我对此无能为力:
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 = ',')
根据我的理解,它会创建字典“阅读器”。如何将此字典子集化为多个字典,将它们按原始csv文件中的标题行拆分?是否有一种简单,优雅,非循环的方式来创建字典列表(甚至是字典字典,帐户ID作为键)?这有意义吗?
喔。请注意标题行不相同,但标题行始终以' ClientAccountID'开头。
感谢@ codie,我现在使用以下内容将csv拆分成几个dicts,基于使用' \ t'分隔符。
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'}
...
所以看起来它正在拆分每个字符,而不是使用逗号分隔符。
答案 0 :(得分:2)
如果我已正确理解您的问题,您就会有一个包含多个表的CSV文件。表由标题行分隔,标题行始终以字符串"ClientAccountID"
开头。
因此,工作是将CSV文件读入字典列表列表。列表中的每个条目都对应于CSV文件中的一个表。
以下是我的表现:
"ClientAccountID"
开头的行来执行此操作。DictReader
这里有一些代码可以将文件读入StringIO
列表中。 (A StringIO
是一个内存文件。它通过将字符串包装到类似文件的界面中来工作。)
from csv import DictReader
from io import StringIO
stringios = []
with open('file.csv', 'r') as f:
stringio = None
for line in f:
if line.startswith('ClientAccountID'):
if stringio is not None:
stringio.seek(0)
stringios.append(stringio)
stringio = StringIO()
stringio.write(line)
stringio.write("\n")
stringio.seek(0)
stringios.append(stringio)
如果我们遇到以'ClientAccountID'
开头的行,我们会将当前的StringIO
放入列表并开始写入新列表。完成后,请记住将最后一个添加到列表中。
不要忘记(正如我在本答案的早期版本中所做的那样)在使用StringIO
写入stringio.seek(0)
后回复StringIO
。
现在可以直接遍历data = [list(DictReader(x, delimiter='\t')) for x in stringios]
来获取字典表。
stringios
对于列表DictReader
中的每个类文件对象,创建一个@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Full Screen and remove toolbar
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
}
并将其读入列表。
如果您的数据太大而无法容纳到内存中,那么修改此方法并不难。使用生成器代替列表并逐行进行处理。
答案 1 :(得分:1)
如果您的数据不是逗号或制表符分隔符,则可以使用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)))