0

我有一组文本文件,我试图对其进行排序并从中获取输出。这个想法是这样的:我有两个文件包含稍微匹配的数据,例如

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>
4

1 回答 1

1

假设你的文件是一系列的行,每一行看起来像你写的,即

000892834     13.663      0.098      0.871      0.093      0.745      4.611       4795

然后,您可以使用 去除前导0s lstrip()。当你读取文件时,你得到的不是整数,而是字符串,所以你必须去掉0字符。(或者,您可以将该数字与尾随0s 转换为整数,然后将其重新转换为字符串以再次写入,但您不需要。)

使用字典按 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")

如果您的数据在第二个文件中具有不在第一个文件中的键,则应使用defaultdictformergedData代替。(这解决了您编辑中的#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只要确保它返回TrueFalse.


编辑:再想一想,基于 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())的兴奋中,我忘记了它可以更简单。我也只拆分线路一次,而不是多次。

于 2013-07-03T16:16:06.027 回答