将CSV转换为TDV - 格式化问题

时间:2013-06-04 19:34:07

标签: python

我正在使用CSV文件中的某些值创建制表符分隔文件。 CSV文件包含上个月发出的所有订单,我需要正确格式化以便能够导入当前使用的会计软件。以下是CSV文件中的数据示例:

Customer    Order Number    Item Line Number    Quantity    Product Description

cust1       Order #1                1               40              desc1
cust1       Order #2                1               101             desc2
cust2       Order #3                1               3               desc3
cust2       Order #3                2               8               desc3
cust2       Order #3                3               8               desc3
cust1       Order #4                1               75              desc4

现在,对于Order Number的每个系列,我需要创建一个TDV文件的一部分,如下所示:(忽略括号,这些只是为了显示值来自上面)

1       cust1           HA5ZV1          Desc1           Due Date        ...
2       1 (Item #)      40 (Qty)        ...             ...             ...

1       cust1           HA6A17          Desc2           Due Date        ...
2       1 (Item #)      101 (Qty)       ...             ...             ...

1       cust2           HA6AM1          Desc3           Due Date        ...
2       1 (Item #)      3 (Qty)         ...             ...             ...
2       2 (Item #)      8 (Qty)         ...             ...             ...
2       3 (Item #)      8 (Qty)         ...             ...             ...

希望这是有道理的。到目前为止我所做的是从原始的CSV文件中创建一个字典,但是对于如何遍历我的字典并写入标题(标有“1”的行)一次感到困惑,然后写入值(每次出现相同的Order Number时(标有“2”的行)。到目前为止,这是我的代码:

data = csv.reader(open(import_dir))
fields = data.next()
new_file = export_dir+os.path.basename(import_dir)
tab_file = open(export_dir+os.path.basename(import_dir), 'a+')
for row in data:
    items = zip(fields, row)
    item = {}
    for (name, value) in items:
        item[name] = value.strip()
    tab_file.write('1\t'+item['Customer']+'\t'+item['Order Number']+'\t'
                   +item['Product Description']+'\t'+item['Due Date']+'\n'+
                   '2\t'+item['Item Line Number']+'\t'+item['Quantity']+'\t'+
                   ...

但是此代码将标题数据放在每个订单项之前,而不是仅将其放在每个订单的开头。如果每个客户只订购了一个商品,那就没问题,但由于某些订单有多个订单项,因此会破坏格式。如果有人能够指出我正确的方向,那将是伟大的。谢谢!

1 个答案:

答案 0 :(得分:0)

您希望使用itertools.groupby() tool按客户编号对输入行进行分组:

import csv
import os
from itertools import groupby
from operator import itemgetter

new_file = os.path.join(export_dir, os.path.basename(import_dir))

with open(import_dir) as import, open(new_file, 'ab') as tab_file:
    data = csv.reader(import)
    writer = csv.writer(tab_file, delimiter='\t')

    fields = next(data)
    for customer, rows in groupby(data, key=itemgetter(0)):
        first_row = next(rows)
        item = {f: v.strip() for f, v in zip(fields, first_row)}
        writer.writerow([1, customer, item['Order Number'], item['Product Description'], item['Due Date'])
        writer.writerow([2, item['Item Line Number'], item['Quantity'], ...])
        for i, row in enumerate(rows, 3):
            item = {f: v.strip() for f, v in zip(fields, row)}
            writer.writerow([i, item['Item Line Number'], item['Quantity'], ...])

groupby()返回key函数的当前结果,以及具有该键值的所有行的可迭代结果。一旦下一行不再具有相同的密钥,就会启动一个新组。

我改变的其他事情:

  • 使用with自动关闭打开的文件,无论发生了什么。
  • 使用os.path.join()构建路径
  • 使用csv.writer(..., delimiter='\t')编写制表符分隔文件;它只是另一种CSV方言,真的。
  • 我用dict理解把你的行变成字典。或者,只需使用csv.DictReader()做同样的事情;无需读取第一行中的字段。