Python中CSV对象嵌套For循环异常问题求助
解决CSV嵌套循环仅执行一次的问题
嘿,我明白你遇到的问题了——这事儿我之前处理CSV的时候也踩过一模一样的坑!
问题的核心其实很简单:csv.reader()返回的是迭代器,不是普通的列表。迭代器有个特性,就是只能被完整遍历一次。当你第一次在内层循环里把spamreader1从头到尾跑完之后,这个迭代器就被“耗尽”了,后面外层循环再想进去遍历它,就再也拿不到任何元素了。而普通列表不一样,它是可重复迭代的序列,每次循环都会从头开始,所以你用[1,2,3]测试时一切正常。
给你几个实用的解决方案,你可以根据自己的场景选:
方案1:把CSV内容转成列表保存(最省心)
直接把两个CSV的内容先读取到列表里,这样每次嵌套循环都能从头遍历第二个CSV的内容:
import csv # 读取第一个CSV并转为列表,with语句会自动关闭文件 with open('/Users/rene/Downloads/Test/Export.csv', newline='', encoding='windows-1252') as csvfile: spamreader = list(csv.reader(csvfile, dialect='excel', delimiter=';')) # 读取第二个CSV并转为列表 with open('/Users/rene/Downloads/Test/Transfer.csv', newline='', encoding='windows-1252') as csvfile1: spamreader1 = list(csv.reader(csvfile1, dialect='excel', delimiter=';')) # 现在嵌套循环就能正常工作啦 for row in spamreader: print("1row:"+row[1]) for row1 in spamreader1: print("2row:"+row[1]) print("2row1:"+row1[0])
这里我换成了with语句,它会在代码块结束后自动帮你关闭文件,比手动调用close()更安全,也不用记着收尾。
方案2:每次外层循环重新读取第二个CSV(适合大文件)
如果第二个CSV特别大,转成列表会占太多内存,那你可以在外层循环里每次重新打开并读取它:
import csv with open('/Users/rene/Downloads/Test/Export.csv', newline='', encoding='windows-1252') as csvfile: spamreader = csv.reader(csvfile, dialect='excel', delimiter=';') for row in spamreader: print("1row:"+row[1]) # 每次外层循环都重新打开第二个CSV,确保每次都能从头遍历 with open('/Users/rene/Downloads/Test/Transfer.csv', newline='', encoding='windows-1252') as csvfile1: spamreader1 = csv.reader(csvfile1, dialect='excel', delimiter=';') for row1 in spamreader1: print("2row:"+row[1]) print("2row1:"+row1[0])
这个方法的缺点是每次外层循环都要读一遍文件,速度会慢一点,但胜在不占内存,适合处理大型CSV。
额外小建议:优化对比逻辑(效率更高)
如果你的需求是对比两个CSV的部分内容,其实可以不用嵌套循环,先给第二个CSV建个索引字典,这样匹配起来会快很多。比如假设你是用row[1]去匹配row1[0],可以这么写:
import csv # 先把第二个CSV的内容存入字典,用row1[0]作为键 transfer_dict = {} with open('/Users/rene/Downloads/Test/Transfer.csv', newline='', encoding='windows-1252') as csvfile1: spamreader1 = csv.reader(csvfile1, dialect='excel', delimiter=';') for row1 in spamreader1: transfer_dict[row1[0]] = row1 # 遍历第一个CSV,直接查字典找匹配项 with open('/Users/rene/Downloads/Test/Export.csv', newline='', encoding='windows-1252') as csvfile: spamreader = csv.reader(csvfile, dialect='excel', delimiter=';') for row in spamreader: print("1row:"+row[1]) # 检查当前行的关键值是否在字典里 if row[1] in transfer_dict: matched_row = transfer_dict[row[1]] print(f"匹配到的Transfer行:{matched_row[0]}")
这种方法把时间复杂度从O(n*m)降到了O(n+m),数据量大的时候速度差距会非常明显,推荐试试!
内容的提问来源于stack exchange,提问作者Rene
相关产品推荐
相关产品推荐

