嵌套for循环的问题

2 投票
4 回答
2368 浏览
提问于 2025-04-16 01:35

我需要读取两个csv文件,把它们的内容合并,然后把结果写入第三个csv文件。第一个csv文件有五行数据,第一列是用户名(总共有25列)。第二个csv文件也有五行数据,第一列是用户名,第二列是用户ID(只有2列)。

第三个csv文件将包含用户名+用户ID,以及第一个文件剩下的24列数据。

data = open(os.path.join("c:\\transales","AccountID+ContactID-source1.csv"),"rb").read().replace(";",",").replace("\0","")
data2 = open(os.path.join("c:\\transales","AccountID+ContactID-source2.csv"),"rb").read().replace(";",",").replace("\0","")

i = 0
j = 0
Info_Client_source1=StringIO.StringIO(data)
Info_Client_source2=StringIO.StringIO(data2)


for line in csv.reader(Info_Client_source1):
    name= line[1]
    i=i+1
    print "i= ",i
    for line2 in csv.reader(Info_Client_source2):
        print "j = :",j
        j=j+1
        if line[1] == line2[2]:
            continue

结果:

i=  1
j = : 0
j = : 1
j = : 2
j = : 3
j = : 4
j = : 5
j = : 6
i=  2
i=  3
i=  4
i=  5
i=  6
i=  7

为什么当i=2时,第二个循环不执行了呢?我本来希望i=2时,j能从0到6,i=3时,j也能从0到6,等等。

4 个回答

1

更“符合Python风格”的写法是:

filename1 = os.path.join('c:\\transales', 'AccountID+ContactID-source1.csv') 
filename2 = os.path.join('c:\\transales', 'AccountID+ContactID-source2.csv') 

with open(filename1, 'rb') as file1, open(filename2, 'rb') as file2:

    csv1 = csv.reader(file1, delimiter=';')
    csv2 = csv.reader(file2, delimiter=';')

    lookup = { line[0] : line[1:] for line in csv1 }
    joined = [ [uname, uid] + lookup[uname] for (uname, uid) in csv2 ]

print joined

(假设使用的是Python 版本2.7

顺便提一下:第一列的索引是0,而不是1。

1

因为一旦csv.reader读取到文件的末尾,它就不会再继续执行了。

对于像这样的小数据集,你可以很轻松地把数据读进一个列表或字典里,然后对这些数据进行遍历。

6

这是因为你在第一次读取时,把整个StringIO对象的内容都读完了,结果光标停在了字符串的末尾。第二次读取时,里面已经没有东西了,所以你得到的是一个空的读取器。

另外,每次循环内部都调用csv.reader()可能不是个好主意。让我重新整理一下你的代码,然后解释我做的修改:

data = open(os.path.join("c:\\transales","AccountID+ContactID-source1.csv"),"rb").read().replace(";",",").replace("\0","")
data2 = open(os.path.join("c:\\transales","AccountID+ContactID-source2.csv"),"rb").read().replace(";",",").replace("\0","")

source1 = csv.reader(data)
source2 = csv.reader(data2)

for line in source1:
    name= line[1]
    i=i+1
    print "i= ",i
    data2.seek(0)
    for line2 in source2:
        print "j = :",j
        j=j+1
        if line[1] == line2[2]:
            continue

修改内容:

  • 我去掉了创建StringIO对象这个多余的步骤;你可以直接把标准文件句柄传给csv.reader(),这样也能正常工作。(如果你有创建StringIO对象的理由,可以再加回去...)
  • 我把读取器的初始化移到了for循环外面。虽然在外层循环中初始化source1是可以的,但在内层循环中初始化source2就显得很低效。
  • 最重要的是,调用data2.seek(0)会重置底层文件句柄的光标,这样你就可以多次从data2中读取数据。

这里有一个类似的问题在SO上,可能能更好地说明这个想法:

StackOverflow: 在Python中重复读取CSV文件?

希望这能帮到你。:)

撰写回答