嵌套 For 循环遍历 csv 文件
Nested For loop over csv files
我有 2 个来自同一来源的 .csv 数据集。我试图检查第一个数据集中的任何项目是否仍然存在于第二个数据集中。
#!/usr/bin/python
import csv
import json
import click
@click.group()
def cli(*args, **kwargs):
"""Command line tool to compare and generate a report of item that still persists from one report to the next."""
pass
@click.command(help='Compare the keysets and return a list of keys old keys still active in new keyset.')
@click.option('--inone', '-i', default='keys.csv', help='specify the file of the old keyset')
@click.option('--intwo', '-i2', default='keys2.csv', help='Specify the file of the new keyset')
@click.option('--output', '-o', default='results.json', help='--output, -o, Sets the name of the output.')
def compare(inone, intwo, output):
csvfile = open(inone, 'r')
csvfile2 = open(intwo, 'r')
jsonfile = open(output, 'w')
reader = csv.DictReader(csvfile)
comparator = csv.DictReader(csvfile2)
for line in comparator:
for row in reader:
if row == line:
print('#', end='')
json.dump(row, jsonfile)
jsonfile.write('\n')
print('|', end='')
print('-', end='')
cli.add_command(compare)
if __name__ == '__main__':
cli()
假设每个 csv 文件中有 20 个项目。它目前将迭代 40 次并在我期望它迭代 400 次并创建剩余项目报告时结束。
除了迭代之外的一切似乎都在工作。有人想过更好的方法吗?
迭代 40 次听起来恰到好处 - 当您遍历 DictReader
时,您实际上是在遍历包装的文件行,并且一旦完成迭代,它就不会神奇地重置为beginning - 迭代器完成。
这意味着您的代码将开始遍历 comparator
中的第一项 (1),然后遍历 reader
中的所有项 (20),然后从comparator
(1),那么它在 reader
中就没有任何东西可以迭代了,所以它将转到下一个 comparator
行,依此类推,直到它遍历剩余的比较器线 (18) - 总共产生 40 个循环。
如果你真的想遍历所有的行(并且内存不是问题),你可以将它们存储为列表,然后每当你开始一个 for..in
循环时你都会得到一个新的迭代器,所以:
reader = list(csv.DictReader(csvfile))
comparator = list(csv.DictReader(csvfile2))
应该会给你一个即时修复。或者,您可以在 csvfile.seek(0)
.
循环后重置 reader
'steam'
话虽这么说,如果您只想比较行,并且您希望没有多少行会有所不同,您可以加载 csv.reader() 中的第一行以获得 'header' 然后通过直接比较行来完全放弃 csv.DictReader
。然后,当发生更改时,您可以将行弹出到 csv.reader()
中以正确解析它,然后将其映射到 headers table 以获取变量名称。
这在大型数据集上应该快得多,而且通过文件查找可以给您带来好处,即永远不需要在内存中存储比当前 I/O 缓冲区更多的数据。
我有 2 个来自同一来源的 .csv 数据集。我试图检查第一个数据集中的任何项目是否仍然存在于第二个数据集中。
#!/usr/bin/python
import csv
import json
import click
@click.group()
def cli(*args, **kwargs):
"""Command line tool to compare and generate a report of item that still persists from one report to the next."""
pass
@click.command(help='Compare the keysets and return a list of keys old keys still active in new keyset.')
@click.option('--inone', '-i', default='keys.csv', help='specify the file of the old keyset')
@click.option('--intwo', '-i2', default='keys2.csv', help='Specify the file of the new keyset')
@click.option('--output', '-o', default='results.json', help='--output, -o, Sets the name of the output.')
def compare(inone, intwo, output):
csvfile = open(inone, 'r')
csvfile2 = open(intwo, 'r')
jsonfile = open(output, 'w')
reader = csv.DictReader(csvfile)
comparator = csv.DictReader(csvfile2)
for line in comparator:
for row in reader:
if row == line:
print('#', end='')
json.dump(row, jsonfile)
jsonfile.write('\n')
print('|', end='')
print('-', end='')
cli.add_command(compare)
if __name__ == '__main__':
cli()
假设每个 csv 文件中有 20 个项目。它目前将迭代 40 次并在我期望它迭代 400 次并创建剩余项目报告时结束。
除了迭代之外的一切似乎都在工作。有人想过更好的方法吗?
迭代 40 次听起来恰到好处 - 当您遍历 DictReader
时,您实际上是在遍历包装的文件行,并且一旦完成迭代,它就不会神奇地重置为beginning - 迭代器完成。
这意味着您的代码将开始遍历 comparator
中的第一项 (1),然后遍历 reader
中的所有项 (20),然后从comparator
(1),那么它在 reader
中就没有任何东西可以迭代了,所以它将转到下一个 comparator
行,依此类推,直到它遍历剩余的比较器线 (18) - 总共产生 40 个循环。
如果你真的想遍历所有的行(并且内存不是问题),你可以将它们存储为列表,然后每当你开始一个 for..in
循环时你都会得到一个新的迭代器,所以:
reader = list(csv.DictReader(csvfile))
comparator = list(csv.DictReader(csvfile2))
应该会给你一个即时修复。或者,您可以在 csvfile.seek(0)
.
reader
'steam'
话虽这么说,如果您只想比较行,并且您希望没有多少行会有所不同,您可以加载 csv.reader() 中的第一行以获得 'header' 然后通过直接比较行来完全放弃 csv.DictReader
。然后,当发生更改时,您可以将行弹出到 csv.reader()
中以正确解析它,然后将其映射到 headers table 以获取变量名称。
这在大型数据集上应该快得多,而且通过文件查找可以给您带来好处,即永远不需要在内存中存储比当前 I/O 缓冲区更多的数据。