根据属于另一个文件范围内的范围从文件中提取行

根据属于另一个文件范围内的范围从文件中提取行

我有一个 ca 的文件。我需要根据第 2 列和第 3 列(范围的开始和结束)中的值提取 17000 行:

文件_1.txt

NC_018723.3 88839   102219
NC_018723.3 156206  160651
NC_018723.3 160885  165615
NC_018723.3 178410  191119
NC_018723.3 226179  242932
NC_018723.3 243929  310071
NC_018723.3 384020  413475

我有第二个文件,也有范围:

文件_2.txt

8410001 8420000
8420001 8430000
28550001    28560000
28560001    28570000
111910001   111920000
111920001   111930000
209310001   209320000
209320001   209330000
209330001   209340000

我正在寻找一种方法来从 file_1.txt 中提取第 2 列和第 3 列的范围落在 file_2.txt 的范围内的行。

任何想法,将不胜感激。

答案1

TXR 口齿不清解决方案。

首先,file_1.txt增加了一些实际上属于以下范围的范围案例file_2.txt

NC_018723.3 88839   102219
NC_018723.3 156206  160651
NC_018723.3 160885  165615
NC_018723.3 178410  191119
NC_018723.3 226179  242932
NC_018723.3 243929  310071
NC_018723.3 384020  413475

FOO_1 8420001 8430000
FOO_2 8430000 8440000
FOO_3 8430000 8440000
FOO_4 209310001 209320001
FOO_5 209310001 209320000
FOO_6     209310002 209320000
FOO_7 209310002 209319999

跑步:

$ txr soln.tl 
FOO_1 8420001 8430000
FOO_5 209310001 209320000
FOO_6 209310002 209320000
FOO_7 209310002 209319999

代码在soln.tl

(defvarl rtree [tree nil to])

(defun add-range (tree range)
  (tree-insert tree range))

(defun lookup-range (tree range)
  (let* ((iter (tree-begin tree (from range)))
         (node (tree-next iter))
         (found (if node (key node))))
    (if (and found
             (>= (from range) (from found))
             (<= (to range) (to found)))
      found)))

(awk
  (:inputs "file_2.txt")
  (t (fconv i i) (add-range rtree [f 0]..[f 1])))

(awk
  (:inputs "file_1.txt")
  (t (fconv - i i)
     (if (lookup-range rtree [f 1]..[f 2])
       (prn))))

这里的方法是使用二叉搜索树来存储 的范围file_2.txt

TXR Lisp 有一个范围类型:一种带有访问器from和 的二进制单元to。我们可以在 REPL 中探索这个:

1> 10..20
#R(10 20)
2> (typeof *1)
range
3> (from *1)
10
4> (to *1)
20

soln.tl程序中,表达式[tree nil to]构造了一个新的二叉搜索树。使其nil变空,并且to是关键功能。请注意,它是访问to范围字段的函数。我们将把范围对象放入这棵树中,并且它们将在其to字段上设置键控。

函数lookup-range是最复杂的。给定一个输入范围,它确定该范围是否包含在树中存储的范围内。它用于tree-begin开始按顺序遍历树,但忽略所有键(即to字段)低于from输入范围字段的节点。换句话说,我们正在寻找具有最低to字段的节点,该字段大于from我们的搜索范围的字段。

一旦找到该节点,我们就应用简单的重叠测试来确认它。

函数定义之后有两个(awk ..)表达式。第一个awk进程file_2.txt填充树哈希。 Awkfconv运算符用于将字段转换为整数,并[f 0]..[f 1]从中构造一个范围对象。

第二个{awk ...)作业处理file_1.txt,对范围进行查找,打印那些匹配的记录。

因为平衡二叉树用于范围,所以file_2.txt可能很大。

输出中不会保留空格,因为我们用 修改了字段fconv。在 Awk 中,当您分配给字段时,它会通过使用输出字段分隔符连接字段来重新计算记录图像。

为了保留空白,我们可以awk像这样更改第二个。我们引入一个局部变量并使用它来保存记录recsave的值(就像在经典 Awk 中一样)。rec$0

(awk
  (:inputs "file_1.txt")
  (:let recsave)
  (t (set recsave rec)
     (fconv - i i)
     (if (lookup-range rtree [f 1]..[f 2])
       (prn recsave))))

相关内容