读取csv,并根据条件输出到多个csv文件,嵌套条件大于20个元素



我有一个非常大的csv文件,看起来像这样:

Column1;Column2
01;BE
02;ED
12;FD
14;DS
03;ED
04;DF

现在我想读这个csv文件,根据某些标准,我想把它导出到不同的多个csv文件。

我的代码如下:
import csv
output_path=r'C:myfolderlarge_file.csv'
with open(os.path.join(os.path.dirname(output_path),"first_subset_total.csv"), "w", encoding="utf-8", newline='') as 
out_01, open(os.path.join(os.path.dirname(output_path),"excluded_first.csv"), "w", encoding="utf-8", newline='') as 
out_02, open(os.path.join(os.path.dirname(output_path),"pure_subset.csv"), "w", encoding="utf-8", newline='') as 
out_03_a, open(os.path.join(os.path.dirname(output_path),"final_subset.csv"), "w", encoding="utf-8", newline='') as 
out_04_b:

cw01 = csv.writer(out_01, delimiter=";", quoting=csv.QUOTE_MINIMAL)
cw02 = csv.writer(out_02, delimiter=";", quoting=csv.QUOTE_MINIMAL)
cw03_a = csv.writer(out_03_a, delimiter=";", quoting=csv.QUOTE_MINIMAL)
cw04_b = csv.writer(out_04_b, delimiter=";", quoting=csv.QUOTE_MINIMAL)
with open(output_path, encoding="utf-8") as in_f:
cr = csv.reader(in_f, delimiter=";")
header = next(cr) 
cw01.writerow(header)
cw02.writerow(header)
cw03_a.writerow(header)
cw04_b.writerow(header)
for line in cr:
if (line[0][:2] =="01" and ...): cw01.writerow(line)  
if (line[0][:2] =="02"): cw02.writerow(line)  
if (line[0][:2] =="03" and ...): cw03_a.writerow(line)  
if (line[0][:2] =="04" and ...): cw04_b.writerow(line)

现在我的问题是首先我有很多if语句和超过04个文件。还有一些有子集符号,如04_a和04_b。现在我对04个文件进行了处理,远远不止20个。相同数量的if语句。太多了,我得到一个SyntaxError: too many statically nested blocks错误,因为有超过20个嵌套条件。我当前的解决方案是将下一个条件再次放入循环中。这不是一个好的解决方案。这是低效的。然而,我也怀疑我的编码的可读性和我做它的一般方式。那么我怎样才能更有效地实现这一切呢?

问题出在哪里?

所以我不确定我理解你的问题。我假设最初你使用了某种if-else嵌套,产生了syntax error,你提出的解决方案是你的解决方案,但不是那么有效,因为每个if的条件实际上是互斥的。这意味着第一个为真,其余为假,但你仍然检查它们。

简单解决方案如果我正确理解了这个问题,那么解决方案很简单,用elif替换你的ifelifelseif(duh…)的缩写,并允许您避免下面的大型嵌套结构:

# ...
for line in cr:
if (line[0][:2] =="01" and ...): cw01.writerow(line)  
elif (line[0][:2] =="02"): cw02.writerow(line)  
elif (line[0][:2] =="03" and ...): cw03_a.writerow(line)  
elif (line[0][:2] =="04" and ...): cw04_b.writerow(line)

这是真的,这仍然很难阅读,但对齐你的代码,这已经是相当可以接受的。尽管我承认这会导致大量的面条式代码。

更复杂的解决方案(重做你的代码结构)

在我看来,你实际上只有两个参数需要硬编码:输出文件名和相关条件。这是无法避免的。如果我们采取极简主义的方法,这些应该是唯一的"意大利面"。在你的代码中。所有其他多余的代码行都可以避免。

因此,我会首先在文件开头将它们定义为某种可迭代对象,然后在代码中遍历这个列表,避免同一行代码重复20次。

我不认为这与我重写你的代码有关,但这里有一些指针,将给你一些很好的工具来做得很好:

  • 你的可迭代对象可以是以下类型之一:嵌套列表,字典,numpy数组,数据类。我推荐numpy数组,它是易用性和灵活性之间的一个很好的折衷。
  • 你可以使用python lambdas来将你的条件存储在列表中。
  • 您可以使用上下文管理器(with)与可变数量的文件,只有两行使用contexlib.ExitStack,如本答案所示。
  • 你可以使用break退出循环,一旦你发现条件为真,并切换到下一行。

思路如下:

  1. 写你的数组条件和lambdas和文件名(2d)数组
  2. 使用上下文管理器在2行中打开所有输出文件
  3. 遍历打开的文件以获得CSV编写器列表
  4. 使用上下文管理器打开输入文件(就像你已经做的那样)
  5. 遍历CSV编写器以编写头文件
  6. 对于每一行,遍历您的条件,并将该行写入具有相关CSV写入器的文件(这很容易,它应该与您的真实条件具有相同的索引)
  7. (可选)为了增加一点速度,在找到正确的条件后中断条件迭代。