如何检查一个文件中的一个数字范围是否是另一个文件中另一个数字范围的子集?
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 b
或 a 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
我试图找出 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 b
或a 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