如何检查一个文件中的一个数字范围是否是另一个文件中另一个数字范围的子集?

How to check whether one number range from one file is the subset of other number range from other file?

我试图找出 range1 的数字 [a 和 b 列] 是子集还是位于 range2 的列 [b 和 c 列] 之间。

范围1

a        b
15       20
 8       10
37       44
32       37

范围2

    a       b       c
    chr1    6       12
    chr2    13      21
    chr3    31      35
    chr4    36      45

输出:

a       b       c
chr1    6       12       8       10
chr2    13      21       15      20
chr4    36      45       37      44

我想比较 range1[a] 和 range2[b] 以及 range1[b] 和 range2[c]。一对一比较。

例如在第一个 运行 中:range-1 的第一行和 range-2 的所有其他行。但是 range1[a] 应该只与 range2[b] 进行比较,类似地,range1[b] 应该只与 range2[c] 进行比较。基于此,我只写了一个标准:

lbs[i] && lbsf1[j] <= ubs[i] && ubsf1[j] >= lbs[i] && ubsf1[j] <= ubs[i]

r1[a] r2[b] r1[b] r2[c]
15 > 6      20 < 12     False
15 > 13     20 < 21     True
15 > 31     20 < 35     False
15 > 36     20 < 45     False 

我试图从这段代码中学习[如果我们想检查一个数字是否在特定范围内,它是有效的],因此我尝试对两个数字都进行相同的修改。但是没有用,我觉得我无法正确读取第二个文件。

代码:[参考但略有修改]

    #!/bin/bash

awk -F'\t' '
# 1st pass (fileB): read the lower and upper range bounds
FNR==NR { lbs[++count] = +0; ubs[count] = +0; next }
# 2nd pass (fileA): check each line against all ranges.
{ lbsf1[++countf1] = +0; ubsf1[countf1] = +0;

        for(i=1;i<=count;++i)
                {
                        for(j=1;j<=countf1;++j)
                        {
                        if (lbsf1[j] >= lbs[i] && lbsf1[j] <= ubs[i] && ubsf1[j] >= lbs[i] && ubsf1[j] <= ubs[i])
                                { print lbs[i]"\t"ubs[i]"\t"lbsf1[j]"\t"ubsf1[j] ; next }
                        }
                }
}
' range2 range1

这段代码给了我输出:

6       12      8       10
6       12      8       10
6       12      8       10

谢谢。

假设:

  • 输入文件没有 a ba b c 作为第一行(如果这些行确实存在于数据中,我们可以修改建议的代码)
  • range2 中的行没有前导白色 space(如提供的示例所示)
  • 虽然提供的小样本没有证明,但假设 range1 中的一行可能 'match' 与 range2 中的多行并且我们想要打印所有匹配项(如果我们需要在找到第一个 'match')
  • 行后停止处理 range1 行,我们可以修改建议的代码

示例数据:

$ cat range1
15      20
 8      10
37      44
32      37

$ cat range2
chr1    6       12
chr2    13      21
chr3    31      35
chr4    36      45
chr15   36      67             # added to demonstrate multi-match for range1 [ 37 , 44 ]

当前代码的问题:

  • range1 数据加载到一个数组中,然后为从 range1 读取的每一行循环遍历此(不断增长的数组);这个数组是不必要的,因为我们只需要处理来自 range1
  • current
  • 双循环逻辑在打印第一个匹配的记录集时中止(; next);这种过早的取消意味着我们只能看到第一场比赛……一遍又一遍; ; next 可以删除
  • range2 输入处理期间未捕获 range2[a] 列,因此我们无法在最终输出中显示此列

更新 OP 的当前代码以解决这些问题:

awk '
BEGIN   { FS=OFS="\t" }

FNR==NR { chromo[++count]=
          lbs[count]=
          ubs[count]=
          next
        }

        { lb=
          ub=

          for (i=1;i<=count;++i)
              if ( lb >= lbs[i] && lb <= ubs[i] && ub >= lbs[i] && ub <= ubs[i] )
                 print chromo[i],lbs[i],ubs[i],lb,ub
        }
' range2 range1

这会生成:

chr2    13      21      15      20
chr1    6       12       8      10
chr4    36      45      37      44
chr15   36      67      37      44

如果需要对输出进行排序,我们可以修改 awk 代码以将结果存储在另一个数组中,然后在 END {...} 处理过程中对数组进行排序和打印。但为了简单起见,我们将输出通过管道传输到 sort,例如:

$ awk ' BEGIN { FS=OFS="\t" } FNR==NR ....' range2 range1 | sort -V
chr1    6       12       8      10
chr2    13      21      15      20
chr4    36      45      37      44
chr15   36      67      37      44