您可以在r+ 模式下打开文件,这将允许您在不重新打开的情况下读取和写入文件。
简短的(理解起来有点复杂)版本的代码(下面有解释):
with open(r"filename.csv", "r+") as f:
next(f) # skip first line
[*columns] = zip(*((int(i) for i in line.split(",")[1:]) for line in f))
print("MAX", "", *map(max, columns), sep=",", file=f)
print("MIN", "", *map(min, columns), sep=",", file=f)
现在让我们解释一下它是如何工作的。为了获得每列的最大值/最小值,我们必须将列的所有值分组到一个容器中。为了得到行,我们应该用逗号分割每一行并将每个值转换为整数。由于我们不需要第一列的值,我们可以跳过它。所有这些工作都由一行代码完成:
[*columns] = zip(*((int(i) for i in line.split(",")[1:]) for line in f))
同样的,我们可以用更明确的方式来写:
rows = []
for line in f:
row = []
for column in line.split(",")[1:]: # skip first column
row.append(int(column)) # convert string to int
rows.append(row)
columns = list(zip(*rows))
[*columns] = iterable 与columns = list(iterable) 相同。
在我们得到包含每列值的元组列表后,我们可以将max() 和min() 应用于每个元组以获得最大值和最小值。我们可以使用生成器表达式来做到这一点:
(max(column) for column in columns)
(min(column) for column in columns)
或者使用map():
map(max, columns)
map(min, columns)
要将结果写入文件,我们需要将值转换为字符串并使用 str.join() 将它们连接回单个字符串:
max_row = ["MAX", ""] # empty string needed to get double comas
min_row = ["MIN", ""]
for column in columns:
max_row.append(str(max(column)))
min_row.append(str(min(column)))
f.write("\n" + ",".join(max_row))
f.write("\n" + ",".join(min_row))
或者,我们可以使用print()。我们可以unpack 打印我们的结果,将"," 传递给sep 参数,这将使python 使用逗号连接所有参数,并将我们的文件对象传递给file 参数以使其写入文件而不是控制台。
print("MAX", "", *map(max, columns), sep=",", file=f)
print("MIN", "", *map(min, columns), sep=",", file=f)
所以这是答案顶部的无聊版本的代码:
with open(r"filename.csv", "r+") as f:
next(f) # skip first line
rows = []
for line in f:
row = []
for column in line.split(",")[1:]: # skip first column
row.append(int(column)) # convert string to int
rows.append(row)
max_row = ["MAX", ""] # empty string needed to get double comas
min_row = ["MIN", ""]
for column in zip(*rows):
max_row.append(str(max(column)))
min_row.append(str(min(column)))
f.write("\n" + ",".join(max_row))
f.write("\n" + ",".join(min_row))
Upd. 如果要将结果写入单独的文件并添加索引列,您还需要打开一个目标文件进行写入,将源文件的每一行重写到目标(添加它的索引)并将最小值和最大值附加到文件末尾。
修改后的短版代码(变得更加复杂):
with open(r"input.csv") as inp_f, \
open(r"output.csv", "w") as out_f:
out_f.write("NO," + next(inp_f))
[*columns] = zip(*(out_f.write(f"{index},{line.rstrip()}\n") and
(int(i) for i in line.split(",")[1:])
for index, line in enumerate(inp_f)))
print("MAX", "", *map(max, columns), sep=",", file=out_f)
print("MIN", "", *map(min, columns), sep=",", file=out_f)
修改无聊版代码:
with open(r"input.csv") as inp_f, \
open(r"output.csv", "w") as out_f:
out_f.write("NO," + next(inp_f))
rows = []
for index, line in enumerate(inp_f, 1):
out_f.write(str(index) + "," + line)
row = []
for column in line.split(",")[1:]: # skip first column
row.append(int(column)) # convert string to int
rows.append(row)
max_row = ["MAX", ""] # empty string needed to get double comas
min_row = ["MIN", ""]
for column in zip(*rows):
max_row.append(str(max(column)))
min_row.append(str(min(column)))
out_f.write("\n" + ",".join(max_row))
out_f.write("\n" + ",".join(min_row))
更新。我做了一些测试(code)。测试结果(越低越好):
olvin1: 0.687356842
olvin2: 0.5448804249999999
nikeros: 0.7540002289999999
balderman: 0.6384034139999999
因此,此答案中的“无聊”方法展示了最佳性能。