假设你的文件是一系列的行,每一行看起来像你写的,即
000892834 13.663 0.098 0.871 0.093 0.745 4.611 4795
然后,您可以使用 去除前导0
s lstrip()
。当你读取文件时,你得到的不是整数,而是字符串,所以你必须去掉0
字符。(或者,您可以将该数字与尾随0
s 转换为整数,然后将其重新转换为字符串以再次写入,但您不需要。)
使用字典按 ID 对行进行配对,并使其键为列表,其中存储第一个文件中的行和第二个文件中的行。
mergedData = {}
with open('file1.txt', 'r') as file1, open('file2.txt', 'r') as file2, open('mergedData.txt', 'w') as outfile:
for line in file1:
mergedData[line.split()[0].lstrip('0')] = [line]
for line in file2:
mergedData[line.split()[0]].append(" ".join(line.split()[:4]))
for k in mergedData:
outfile.write("\n".join(mergedData[k]) + "\n")
如果您的数据在第二个文件中具有不在第一个文件中的键,则应使用defaultdict
formergedData
代替。(这解决了您编辑中的#1。)
from collections import defaultdict
mergedData = defaultdict(list)
with open('file1.txt', 'r') as file1, open('file2.txt', 'r') as file2, open('mergedData.txt', 'w') as outfile:
for line in file1:
mergedData[line.split()[0].lstrip('0')].append(line)
for line in file2:
mergedData[line.split()[0]].append(" ".join(line.split()[:4]))
...
如果您只需要写入满足特定要求的数据,则可以使用filter()
仅获取满足特定要求的元素。接受一个过滤器函数,如果元素满足该要求,则该filter()
函数必须返回。这是将lambda表达式用于快速内联函数的True
一个很好的更改。
...
filteredMergedData = filter(lambda x: (len(x[1]) == 2) and (int(x[1][0].split()[1]) > 15 and int(x[1][1].split()[1]) > 15), mergedData.iteritems()
for d in filteredMergedData:
outfile.write("\n".join(d[1]) + "\n")
这是相当复杂的,但基本上,它将字典中的键值对转换为元组,(key, value)
并遍历它们,检查 lambda 是否返回True
。lambda 取值部分,即您回忆的列表,并检查第二列是否有大于 15 的值。它必须将这些值转换为,int
因为它们通常是字符串,并且不会与int
. 为了使子索引起作用,您还必须检查以确保值部分包含两行 - 这也为您处理#3。
现在,如果你想把这一切放在一起并支持任意标准和任意文件名,你应该把这段代码放到一个函数中,让它接受四个参数:三个文件名,以及一个函数(是的,你可以接受函数作为参数)充当过滤器功能。
from collections import defaultdict
def mergeData(file1name, file2name, outfilename, a_filter_func):
""" Merge the data of two files. """
mergedData = defaultdict(list)
with open(file1name, 'r') as file1, open(file2name, 'r') as file2, open(outfilename, 'w') as outfile:
for line in file1:
mergedData[line.split()[0].lstrip('0')].append(line)
for line in file2:
mergedData[line.split()[0]].append(" ".join(line.split()[:4]))
filteredMergedData = filter(a_filter_func, mergedData.iteritems())
for d in filteredMergedData:
outfile.write("\n".join(d[1]) + "\n")
# finally, call the function.
filter_func = lambda x: (len(x[1]) == 2) and (int(x[1][0].split()[1]) > 15 and int(x[1][1].split()[1]) > 15)
mergeData('file1.txt', 'file2.txt', 'mergedData.txt', filter_func)
filter_func
如果您想要其他标准,只需传递除该 lambda 之外的其他内容 - 您可以创建一个名为“ def
”的函数,如果您愿意,也可以传递它,例如,如果您有,您可以作为参数def foo(x):
传递。foo
只要确保它返回True
或False
.
编辑:再想一想,基于 lambda 的解决方案需要四次线性迭代。这是一个优化(可能更简单)的版本:
def mergeData(file1name, file2name, outfilename, a_filter_func):
""" Merge the data of two files. """
mergedData = defaultdict(list)
with open(file1name, 'r') as file1, open(file2name, 'r') as file2, open(outfilename, 'w') as outfile:
for line in file1:
splt = line.split()
if a_filter_func(splt[1]):
mergedData[splt[0].lstrip('0')].append(line)
for line in file2:
splt = line.split()
if a_filter_func(splt[1]):
mergedData[splt[0]].append(" ".join(splt[:4]))
for k in mergedData:
outfile.write("\n".join(mergedData[k]) + "\n")
现在a_filter_func
可能很简单:
lambda x: x > 15
在我开始使用“函数式编程”函数(例如filter()
)的兴奋中,我忘记了它可以更简单。我也只拆分线路一次,而不是多次。