自分ならこういう感じにします。
import csv
import glob
def load_items(path):
items = {}
with open(path, encoding='utf-8') as f:
reader = csv.DictReader(f, ['item_id', 'name', 'price'])
for row in reader:
items[row['item_id']] = row
return items
def iter_sales_rows(pattern):
for path in sorted(glob.glob(pattern)):
with open(path, encoding='utf-8') as f:
reader = csv.DictReader(f, ['purchase_id', 'user_id', 'item_id', 'quantity', 'sale_date'])
for row in reader:
yield row
def main():
items = load_items('input/items.csv')
with open('output/sales.csv', mode='w', encoding='utf-8') as f:
writer = csv.DictWriter(f, ['purchase_id', 'user_id', 'item_id', 'name', 'price', 'quantity', 'sale_date'], extrasaction='ignore')
for row in iter_sales_rows('input/sales_raw_201611*.csv'):
item_id = row['item_id']
if row['item_id'] in items:
output_row = {**row, **items[item_id]}
writer.writerow(output_row)
if __name__ == '__main__':
main()
ここでは csv.DictReader
を使いました。 CSV を1行ずつ読んで辞書で返してくれます。たとえば csv.DictReader(f, ['item_id', 'name', 'price'])
で作ると {'item_id: 1, 'name': '商品1', 'price': '100'}
のような辞書が次々に得られます。
また、入れ子の処理を分割では、売上データの書き出し処理のwith文の中にwith文が入っているので、この箇所を分割するのかなと思うのですが、どのように分割すると良いのかイメージが付かない状況になります。
まず売上データをすべて読み込んでリストに入れてしまうのも一つの手です。入力ファイルが何百MBもあるというのでなければ十分メモリに乗ります。ここでは別の方法、メモリ消費を抑えたいときの書き方として iter_sales_rows()
でジェネレータを使ってみました。 for row in iter_sales_rows('input/sales_raw_201611*.csv'):
が1回ループするごとにファイルから1行ずつ読んでいきます。