我是一个Python新手,遇到了一个任何地方都找不到答案的问题。在
我正在尝试编写基于另一个文件过滤一组文件的代码。文件是具有多行和多列的数组。我希望从数据文件中删除与筛选文件中某些列的行匹配的行。在
代码是:
paths = ('filepaths.txt')#file that has filepaths to open
filter_file = ('filter.txt')#file of items to filter
filtered = open('filtered.txt','w') #output file
filtering = open(filter_file, 'r').readlines()
for f in filtering:
filt = f.rstrip().split('\t')
files = open(paths).read().splitlines()
for file in files:
try:
lines = open(file,'r').readlines()
for l in lines:
data = l.rstrip().split('\t')
a = [data[0], data[5], data[6], data[10], data[11]] #data columns to match
b= [filt[0], filt[1], filt[2], filt[3], filt[4]] #filter columns to match
for i,j in zip(a,b): #loop through two lists to filter
if i != j:
matches = '\t'.join(data)
print (matches)
filtered.write(matches + '\n')
filtered.close()
代码执行,但没有按我的要求工作。我得到的是每个文件的最后一行,重复5次。在
很明显,我遗漏了一些东西。我不确定zip是否是正确的函数,或者其他更好的功能。如果有什么建议,我将不胜感激。在
编辑:
过滤器的样本输入:
^{pr2}$要筛选的文件的示例输入(多余的列保留):
TKTL1 8277 broad.mit.edu 37 X 153558089 153558089 + 3'UTR SNP G C C
MPP1 4354 broad.mit.edu 37 X 154014502 154014502 + Silent SNP G A A
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
示例输出(多余列已关闭):
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
BRCC3 79184 broad.mit.edu 37 X 154306908 154306908 + Silent SNP A T T
我将从一些简单的更改开始,然后演示如何使用内置工具,如Python的
csv
库和any
函数来简化代码。在这里有一个版本,它稍微清理了一些东西,使用了正确的逻辑,但是没有引入太多新的语言特性。它使用的主要新功能是
with
语句(退出时自动关闭文件),并直接在文件上迭代,而不是使用readlines
:我们做了好几次的一件事就是使用for循环来建立一个列表。有一个更简洁的表达方式,它做同样的事情叫做列表理解。因此,使用它,我们可以:
^{pr2}${tab>但也可以注意Python的tab}格式
当您迭代它时,它返回由分隔符分隔的字段列表。请注意,我是在
b
模式下打开的;这是否会产生影响取决于您的平台,但是如果是这样的话,csv文档需要注意这是必需的。在您可以对数据文件使用类似的方法,甚至可以选择使用
writer
类编写过滤后的输出。在最后,}内置函数接受iterables,如果iterables的任何或所有内容的计算结果为}。您可以使用这些来删除嵌套的for循环,使用一个生成器表达式-这是一个类似于列表理解的结构,只是它是惰性求值的,这很好,因为}将短路。下面是一个写这个的方法:
any
和{True
,则返回{any
和{在这个特殊的例子中,我并没有从这个短路中得到多少好处,因为我使用
zip
来构建一个实际的元组列表。但对于这样的短列表来说,它是好的,zip
在内存中已经存在的列表上的性能优于itertools.zip
(懒惰求值版本)。在然后,您可以使用
any
将该行与所有筛选器进行简明比较,只要有一个匹配,就会进行短路:但这仍然是过分的杀伤力。
match
函数强制要求其两个输入中的所有元素都必须相等,但是如果您测试两个列表是否相等,这就是Python自动执行的部分操作。我编写的match
函数将允许长度不等的列表匹配,只要较长列表的起始元素都匹配较短的列表,而Python list equality则不匹配,但这不是问题所在。所以这也会起作用:或者,如果过滤器比正常过滤器更长,您可能希望容忍:
非切片版本也可以通过直接列表成员资格测试编写:
另外,正如Blckknght指出的那样,Python有一种更好的方法来快速测试类似于一行的东西是否匹配许多模式中的任何一种,即
set
数据类型,它使用常量时间查找。与csv
库或split
返回的列表一样,列表不能是集合的成员,但元组可以,只要元组的成员本身是可散列的。因此,如果您将过滤器和数据行子集转换为元组,您可以维护一个集合而不是一个列表,并且可以更快地检查它。为此,必须将每个筛选器转换为元组:然后,将
a
定义为元组:如果您使用
csv.writer
实例来编写输出,您甚至可以使用writerows
方法和生成器表达式进一步合并它:总而言之,我会这样做:
当您创建
filt
时,您正在创建一个字符串变量并多次重写它。尝试更换与
^{pr2}$现在,
filt
是一个列表列表,每个元素代表一行。例如,filt[0]
将给出第一行,filt[2][3]
将给出第三行的第四列。您可能需要修改程序的其余部分才能正常工作。在相关问题 更多 >
编程相关推荐