如何循环到字典中的字典以指定方式组织来自 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
因此索引需要是 0
和 1
。如果我们将 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:]
。 (您可以一起取消 key
和 values
,只引用 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 年后回来理解你做了什么。出于这个原因,我还建议您对您所做的发表评论。
我制作了一个脚本:
-从 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
因此索引需要是 0
和 1
。如果我们将 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:]
。 (您可以一起取消key
和values
,只引用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 年后回来理解你做了什么。出于这个原因,我还建议您对您所做的发表评论。