如何循环到字典中的字典以指定方式组织来自 CSV 的数据

How to loop to dictionary in dictionary to organize data from CSV in specified way

我制作了一个脚本:

-从 CSV 文件中获取数据-按数据文件第一列中的相同值对其进行排序 -在不同模板文本文件的特定行中插入排序数据 - 将文件保存为尽可能多的副本,因为数据文件的第一列中有不同的值下图显示了它是如何工作的:

但是我还有两件事需要做。当在如上所示的单独文件中时,数据文件的第二列中有一些相同的值,则此文件应插入第三列中的值,而不是重复第二列中的相同值。在下面的图片中,我展示了它应该是什么样子:

我还需要在某处添加数据文件中第一列的分隔值“_”。

有数据文件:

111_0,3005,QWE
111_0,3006,SDE
111_0,3006,LFR
111_1,3005,QWE
111_1,5345,JTR
112_0,3103,JPP
112_0,3343,PDK
113_0,2137,TRE
113_0,2137,OMG

还有我编写的代码:

import shutil
 
with open("data.csv") as f:
    contents = f.read()
    contents = contents.splitlines()
 
values_per_baseline = dict()
 
for line in contents:
    key = line.split(',')[0]
    values = line.split(',')[1:]
    if key not in values_per_baseline:
        values_per_baseline[key] = []
    values_per_baseline[key].append(values)
 
for file in values_per_baseline.keys():
    x = 3
    shutil.copyfile("of.txt", (f"of_%s.txt" % file))
    filename = f"of_%s.txt" % file
    for values in values_per_baseline[file]:
        with open(filename, "r") as f:
            contents = f.readlines()
            contents.insert(x, '      o = ' + values[0] + '\n          ' + 'a = ' + values[1] +'\n')
        with open(filename, "w") as f:
            contents = "".join(contents)
            f.write(contents)
            f.close()

我一直在尝试制作类似列表字典的字典,但我无法以正确的方式实现它以使其工作。

当我运行你的代码时,我得到这个错误:

    contents.insert(x, '      o = ' + values[0] + '\n          ' + 'a = ' + values[3] +'\n')
IndexError: list index out of range

让我们想想这个错误是从哪里来的。它是列表中的 IndexError。此行中使用的唯一列表是 values,因此这似乎是开始查找的好地方。

要进行调试,您可以考虑在出现错误的行之前添加如下内容:

            print(values)
            print(values[0])
            print(values[3])

这给出了

['3005', 'QWE']
3005
Traceback (most recent call last):
  File "qqq.py", line 25, in <module>
    print(values[3])
IndexError: list index out of range

所以问题出在 values[3],这是有道理的,因为 len(values)==2 因此索引需要是 01。如果我们将 values[3] 更改为 values[1],那么我想你会得到你想要的。例如:

$ cat of_111_0.txt
line
line
line
      o = 3006
          a = LFR
      o = 3006
          a = SDE
      o = 3005
          a = QWE
line
line
line
line
line

要进入问题的下一步,我建议您将第一个循环更改为:

for line in contents:
    key = line.split(',')[0]
    values = line.split(',')[1:]
    if key not in values_per_baseline:
        values_per_baseline[key] = {}
    if values[0] not in values_per_baseline[key]:
        values_per_baseline[key][values[0]] = values[1]
    else:
        values_per_baseline[key][values[0]] += '<COMMA>' + values[1]

这使您的字典成为:

{'111_0': {'3005': 'QWE', 
           '3006': 'SDE<COMMA>LFR'}, 
 '111_1': {'3005': 'QWE', 
           '5345': 'JTR'}, 
 '112_0': {'3103': 'JPP', 
           '3343': 'PDK'}, 
 '113_0': {'2137': 'TRE<COMMA>OMG'}}

然后在写入文件时,您需要将循环更改为:

        for key in values_per_baseline[file]:
            contents.insert(x, f'{6*sp}o = {key}\n{10*sp}a = {values_per_baseline[file][key]}\n')

你的文件现在看起来像:

line
line
line
      o = 3006
          a = SDE<COMMA>LFR
      o = 3005
          a = QWE
line
line
line
line
line

您可以做的其他事情

现在,您可以采取一些措施来简化代码,同时保持代码的可读性。*

  • 在第 10 行和第 11 行,不需要使用两次 line.split。只需添加一行类似 split_line = line.split(',') 的行,然后添加 key = split_line[0]values = split_line[1:]。 (您可以一起取消 keyvalues,只引用 split_line[0]split_line[1],但这会降低您的代码的可读性。
  • 在第 17 行,您在 every 循环中定义了 x。把它从循环中取出来。
  • 在第 12 行和第 13 行,您首先使用 (f"of_%s.txt" % file),然后在下一行的文件中定义它。建议先定义filename,再定义shutil.copyfile("of.txt", filename)。另外,您使用的 f-strings 不正确。你可以只写 filename = f"of_{file}.txt".
  • 在第 23 行,您可以将 insert 命令更改为 f-string(如果您觉得它更易读)。例如:contents.insert(x, f'{6*sp}o = {values[0]}\n{10*sp}a = {values[1]}\n')
  • 最后,在您的 for values in values_per_baseline.keys() 循环中,您打开和关闭文件的次数超出了您的需要。您可以重新排序您的操作:
    with open(filename, "r") as f:
        contents = f.readlines()
        for values in values_per_baseline[file]:
            contents.insert(x, '      o = ' + values[0] + '\n          ' + 'a = ' + values[1] +'\n')
    with open(filename, "w") as f:
        contents = "".join(contents)
        f.write(contents)
        f.close()

*对于像这样的短脚本,我认为确保它可读性比确保它有效更重要,因为你会希望能够在 3 周或 3 年后回来理解你做了什么。出于这个原因,我还建议您对您所做的发表评论。