在几个标题行上拆分csv中的行

时间:2015-10-23 15:55:12

标签: python csv dictionary

我对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'}
...

所以看起来它正在拆分每个字符,而不是使用逗号分隔符。

2 个答案:

答案 0 :(得分:2)

如果我已正确理解您的问题,您就会有一个包含多个表的CSV文件。表由标题行分隔,标题行始终以字符串"ClientAccountID"开头。

因此,工作是将CSV文件读入字典列表列表。列表中的每个条目都对应于CSV文件中的一个表。

以下是我的表现:

  1. 将包含多个表的单个CSV文件拆分为多个文件,每个文件都有一个表。 (这些文件可以在内存中。)通过查找以"ClientAccountID"开头的行来执行此操作。
  2. 使用DictReader
  3. 将每个文件读入字典列表

    这里有一些代码可以将文件读入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)))