我有一组文本文件,我正在尝试排序并从中获取输出。这个想法是这样的:我有两个包含轻微匹配数据的文件,例如
File 1:
000892834 13.663 0.098 0.871 0.093 0.745 4.611 4795
File 2:
892834 4916 75 37 4857 130 128 4795 4.61 -0.09 0 0
匹配两者的主要因素是第一个数字,它是一个ID号,在文件1前面的000文件中没有变化。我需要搜索这两个文件,提取与该ID匹配的行并将结果输出到一个文本文件,我可以在其中并排显示结果,例如:
output:
000892834 13.663 0.098 0.871 0.093 0.745 4.611 4795
892834 4916 75 37
上面输出的第二部分不是拼写错误,我还需要脚本删除文件2中第四个数据点后每行的部分。我一直在争论是否应该首先将这两个文件放入列表然后以列表理解方式通过它们,或者使用类似csv读取器的东西是否更好。谢谢你提供的所有帮助。
编辑: 1)两个列表中的值(ID号)不完全相同,列表2具有不同的ID,列表1也是如此。 2)此外,如果某些部分不符合标准,我需要过滤掉整行数据,例如,如果某行中的第2列不符合要求,则忽略该行。 3)另外,我刚刚发现我需要省略任何不在file1和file2中的ID,所以如果存在上面匹配的ID,则需要包含它,否则必须保留超出最终的文本文件。
示例:
for mergedData[(a, b, c), (e, f, g), .....]:
if mergedData[(a, e, (all first sub-indices))] > 15
<delete the entire line from the .txt file> and/or <create a new text file containing only lines that meet the criteria>
答案 0 :(得分:1)
假设你的文件是一系列行,每一行看起来都像你写的那样,即
000892834 13.663 0.098 0.871 0.093 0.745 4.611 4795
然后,您可以使用lstrip()
删除前导0
。当你读取文件时,你没有获得整数,你得到字符串,所以你必须删除0
个字符。 (或者,您可以将带有尾随0
的数字转换为整数,然后将其重新转换为字符串以再次写入,但您不需要。)
使用字典按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
代替mergedData
。 (这解决了编辑中的#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()
采用过滤函数,如果元素满足该要求,则必须返回True
。对于快速内联函数,使用lambda表达式是一个很好的更改。
...
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)
,并通过它们迭代元组,检查是否拉姆达返回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)
如果你想要其他标准,只要传递lambda filter_func
以外的其他内容 - 你可以创建一个名为“def
”的d函数,如果你愿意,也可以传递它,例如如果你有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()
),我忘了它可能更简单。我也只拆分了一次,而不是多次。