我想从file1.txt
中提取范围与file2.txt
匹配的数据。
$ cat file1.txt
gene position type
DDX 0 A
DDX 1 B
DDX 2 C
DDX 3 D
DDX 4 E
DDX 5 F
ABC 0 A
ABC 1 B
ABC 2 C
ABC 3 D
ABC 4 E
ABC 5 F
$ cat file2.txt
gene start_position end_position
DDX 2 4
ABC 1 2
预期产出:
gene position type
DDX 2 C
DDX 3 D
DDX 4 E
ABC 1 B
ABC 2 C
因此,在file1.txt
中,我希望从DDX
,2
和3
以及所有4
获取所有ABC
职位1
和2
。
我不太确定如何将其与file2.txt
匹配。
我只知道使用awk的手动方式。例如,
awk -F '\t' '$1=="DDX" && $2>=2 && $1<=4' file1.txt
我有一个巨大的列表可以匹配file1.txt
和file2.txt
。
答案 0 :(得分:3)
我有一个巨大的列表来匹配file1.txt和file2.txt
在这种情况下,从file2构建一个awk脚本(使用awk),然后处理file1。
如你所述,你需要的是一系列陈述,如:
$1=="DDX" && 2 <= $2 && $3 <= 4
例如,将此输出传递给awk:
$ awk 'NR > 1 { \
printf( "$1==\"%s\" && %d <= $2 && $2 <= %d {print; next;}\n", $1, $2, $3 ) \
}' file2.txt
$1=="DDX" && 2 <= $2 && $2 <= 4 {print; next;}
$1=="ABC" && 1 <= $2 && $2 <= 2 {print; next;}
处理file2一次,file1处理一次,生成的脚本一找到匹配就移动到下一个输入行。没有排序,我怀疑你会跑得快得多。
顺便说一句,我重新安排了你的不平等,使a < b && b < c
形式模仿数学,a < b < c
。如果采用该形式,您可能会发现避免错误,因为它将边界放在边缘。
答案 1 :(得分:1)
以下DDX
逻辑应该适合您。一个更通用的逻辑,而不是比较实际的字符串,可以扩展到更多类型,然后只是ABC
或awk 'BEGIN{delete start; delete stop; printf "gene position type\n"} \
FNR==NR && NR > 1 {start[$1]=$2; stop[$1]=$3; next}(($1 in start) && (($2 >= start[$1]) && ($2 <= stop[$1]))){print}'
file2.txt file1.txt
gene position type
DDX 2 C
DDX 3 D
DDX 4 E
ABC 1 B
ABC 2 C
awk
逻辑是构建一个表格,即start
,stop
和file2.txt
中的数组,其中包含来自FNR==NR && NR > 1 {start[$1]=$2; stop[$1]=$3; next}
的每种基因类型的起始和结束范围。
file2.txt
部分从($1 in start) && (($2 >= start[$1]) && ($2 <= stop[$1]))
跳过标题,并为每个基因类型构建具有开始和停止范围的表。
file1.txt
上的git branch -v
用于解析其上的数组内容,其中存在基因类型且开始和结束范围在允许的限制范围内。
答案 2 :(得分:1)
使用GNU AWK&#39; arrays of arrays:
awk -vi=0 '
$1 == "gene" { if (++i == 2) print; next }
i == 1 { g[$1][0] = $2; g[$1][1] = $3 }
i == 2 { if ($2 >= g[$1][0] && $2 <= g[$1][1]) print }
' file2.txt file1.txt
i
变量表示读取的标题数:
i = 0
:目前尚未读取任何标题,i = 1
:读取了file2.txt
的标题; i = 2
:读取file1.txt
的标题。假设如果第一个字段等于"gene"
,那么记录就是标题。您可能需要调整此条件。
对于第一个输入文件(file2.txt
),脚本会将范围的值收集到多维数组g
中,其中第一个键引用第一个字段({{ 1}}),第二个键指的是较低的(gene
)或较高的(0
)限制。
对于第二个输入文件(1
),脚本会检查第二个字段是否与当前file1.txt
的范围匹配,并打印记录(如果匹配)。
对于非GNU AWK,您可以通过将gene
替换为g[$1][0]
来模拟多维数组,将g[$1,0]
替换为g[$1][1]
。在这种情况下,键与g[$1,1]
内部变量连接(顺便说一句,您可以将其覆盖为任何其他AWK变量)。
我注意到您正在使用字段分隔符的选项卡。但问题中的示例内容不包含选项卡。所以我跳过设置SUBSEP
。
答案 3 :(得分:1)
您可以使用多维度数组来存储file2
的最大和最小范围,以使用file1
来过滤awk one-liner
的结果,如下所示:
awk '(NR==FNR){if(FNR>1){f[$1];p[$1,"sp"]=$2;p[$1,"ep"]=$3};next}(FNR == 1 || ($1 in f && $2 >= p[$1,"sp"] && $2 <= p[$1,"ep"]))' file2.txt file1.txt
gene position type
DDX 2 C
DDX 3 D
DDX 4 E
ABC 1 B
ABC 2 C
答案 4 :(得分:1)
根据您对 huge 的定义,这也可能就足够了:
$ awk 'FNR==NR { lo[$1]=$2; hi[$1]=$3; next } # store low and hi values
FNR==1 || ($1 in lo) && $2>=lo[$1] && $2<=hi[$1] # print if between
' file2 file1
gene position type
DDX 2 C
DDX 3 D
DDX 4 E
ABC 1 B
ABC 2 C
此解决方案希望关键字中的范围是连续的,而不是:
gene start_position end_position
ABC 1 2
ABC 4 5
此解决方案无法容忍范围内的差距。
答案 5 :(得分:1)
awk 'FNR == NR { m[$1] = $2; M[$1] = $3; next }
FNR == 1 || $2>=m[$1] && $2<=M[$1]
' file2.txt file1.txt
注意强>
FNR == NR
在读取第一个文件时,NR计算所有行,其中FNR只是当前文件中的一个m[$1] = $2; M[$1] = $3
记住每个标签(条目/索引)的2个数组的限制next
对待下一行FNR == 1 || $2>=m[$1] && $2<=M[$1]
如果第1行(由于前一个next
而产生的第二个文件)或位置($ 2)在相应标签的限制m和M之间($ 1)print
]测试模式的默认操作是打印整行(打印$ 0)ps:在发帖后发现我的解决方案几乎与@jamesbrown相同,抱歉