Python逐行迭代csv,同时跟踪下一行的内容

时间:2014-12-04 21:36:07

标签: python csv

我有一个具有以下结构的csv:

user_id,user_name,code
0001,user_a,e-5
0001,user_a,s-N
0002,user_b,e-N
0002,user_b,t-5

我想迭代文件,以便在处理用户之后,在到达下一个用户之前,根据已处理的用户code执行一些额外的工作。用户可以有多个条目,条目数可以是1到n

例如,当我们处理用户时,我们会跟踪用户已识别/提及的代码的第一个字母。我已将其添加到列表中。我们需要确保在处理特定用户(其用户级别)后重置此列表。

作为示例,我可以考虑user_id 0001,在我到达0002行后,我想添加更多与用户0001相关的行,其中这些新行包含我们尚未见过的代码之前:

以下是我尝试完成此操作的方法:

    with open(os.path.expanduser('out_put_csv_file.csv'), 'w+') as data_file:
        writer = csv.writer(data_file)
        writer.writerow(('user_id', 'user_name', 'code'))
        l_file = csv.DictReader(open('some_file_name'))
        previous_user = None
        current_user = None
        tracker = []
        for row in l_file:
            current_user = row['user_id']
            tracker.append(row['code'].split('-')[0])
            writer.writerow([row['user_id'], row['user_name'], row['code']])
            if current_user != previous_user:
                for l_code in list_with_all_codes:
                        if l_code not in tracker:
                               writer.writerow([row['user_id'], row['user_name'], l_code])
                tracker = []
            previous_user = current_user

问题在于:我得到以下信息:

user_id,user_name,code
0001,user_a,e-5
0001,user_a,n
0001,user_a,t
0001,user_a,i
0001,user_a,s #don't want this
0001,user_a,s-N
0002,user_b,e-N
0002,user_b,n
0002,user_b,t # don't want this
0002,user_b,i
0002,user_b,ta-5

而不是那个,我想要的是

    user_id,user_name,code
    0001,user_a,e-5
    0001,user_a,n
    0001,user_a,t
    0001,user_a,i
    0001,user_a,s-N
    0002,user_b,e-N
    0002,user_b,n
    0002,user_b,i
    0002,user_b,ta-5

我在这里做错了什么?什么是实现这一目标的最佳方式?

2 个答案:

答案 0 :(得分:1)

您的问题是您在意识到需要为旧用户填写之前为新用户编写一行数据...然后使用新用户名编写旧用户数据。

由于您要编写有关前一个用户的多位数据,因此您需要保留他/她的整行。当您看到新用户时,请在执行任何其他操作之前为旧用户写入数据(使用他的信息)。当没有任何以前的用户可以处理时,第一个用户有一个特例。

import os
import csv

open('some_file_name', 'w').write("""user_id,user_name,code
0001,user_a,e-5
0001,user_a,s-N
0002,user_b,e-N
0002,user_b,t-5
""")

list_with_all_codes = ['e', 's', 'n', 't', 'a']

def set_unused_codes(writer, row, tracker):
    for l_code in list_with_all_codes:
        if l_code not in tracker:
            writer.writerow([row['user_id'], row['user_name'], l_code])

with open(os.path.expanduser('out_put_csv_file.csv'), 'w+') as data_file:
    writer = csv.writer(data_file)
    writer.writerow(('user_id', 'user_name', 'code'))
    l_file = csv.DictReader(open('some_file_name'))
    previous_row = None
    tracker = []
    for row in l_file:
        if not previous_row:
            previous_row = row
        if row['user_id'] != previous_row.get('user_id'):
            set_unused_codes(writer, previous_row, tracker)
            previous_row = row
            tracker = []
        tracker.append(row['code'].split('-')[0])
        writer.writerow([row['user_id'], row['user_name'], row['code']])
    set_unused_codes(writer, row, tracker)

print(open('out_put_csv_file.csv').read())

输出是......

user_id,user_name,code
0001,user_a,e-5
0001,user_a,s-N
0001,user_a,n
0001,user_a,t
0001,user_a,a
0002,user_b,e-N
0002,user_b,t-5
0002,user_b,s
0002,user_b,n
0002,user_b,a

如果您不清楚您的遗失代码的编写顺序,您可以使用集合来加快处理速度微不足道的数量(我是否过度宣传了这些?!)

set_of_all_codes = set(list_of_all_codes)
... the for loop ...

    for code in set_of_all_codes - set(tracker):
        writer.writewrow(...)

答案 1 :(得分:1)

在知道完成当前数据单元之前需要查看下一个数据单元时的常见模式如下(在用例之后松散草图)

oldname = ""
data = []

for row in input:
    n,name,code = row.split(',')
    if name != oldname:
        if data: flush(data)
        data = []
        oldname = name
    update(data,n,name,code)
# remember to flush the data buffer when you're done with your file
flush(data)

data可以是列表列表,如

def update(data, n, name, code):
    if not data:
       data.append(n)
       data.append(name)
       data.append([code])
    else:
       data[2].append(code)

关于flush,如果您不知道如何订购输出(请在Q之后重新评论),我也不会这样做。但这只是迭代data[2]和{ {1}},您已经在原始代码中做了类似的事情。