繁体   English   中英

使用awk打印两对在两列之间具有重叠值范围的记录对

[英]Using awk to print pairs of records having overlapping range of values between two columns

我有与start($ 6)和stop($ 7)范围相对应的不同记录。 我要做的是打印出所有具有重叠范围的记录对。

例如,我的数据如下:

id1 0   376 . scaffold1 5165761 5166916 
id2 0   366 . scaffold1 2297244 2298403 
id3 155 456 . scaffold1 692777  693770 
id4 185 403 . scaffold1 102245  729675

我想要的是这样的结果

id3 id4

因为id4的范围与id3重叠。 我一直在互联网上搜索解决方案,但似乎没有任何办法可以解决我的问题。

如果有人提出建议,我将不胜感激。


在遵循以下答复中的一些建议后,我确​​实尝试了此代码,该代码确实有效!

awk '{start[$1]=$6;stop[$1]=$7;} END {for(i in start) {for(j in stop) {if(start[i] >= start[j] && start[i] <= stop[j]) print i,j}}}' file | awk '{if($1!=$2) print}' -

处理时间非常短...对于具有1400条记录的文件,甚至不到1分钟就完成了。

此解决方案需要GNU awk

{
    start = $6 * 10 + 5;
    stop = $7 * 10;
    data[start] = data[start] " " $1;
    data[stop] = data[stop] " " $1;
}
END {
    PROCINFO["sorted_in"] = "@ind_num_asc";
    for (d in data) {
        count = split(data[d], fields);
        for (i in fields) {
            id = fields[i];
            if (d % 10 == 5) { # start
                for (s in started) {
                    print s, id;
                }
                started[id] = 1;
            } else { # stop
                delete started[id];
            }
        }
    }
}

基本思想是:将开始标记和停止标记(我称它们为索引,可能是一个错误的选择)放在单个数组中,并根据其索引对该数组进行排序。 然后,遍历数组。 如果遇到“开始”标记,请将其放在另一个数组中(称为“开始”)。 如果遇到“停止”标记,请将其从该阵列中删除。 现在,如果遇到“开始”标记,则该间隔与“开始”数组中当前的所有间隔重叠,因此请打印出匹配项。 通过确保“停止”标记在具有相同原始索引的“开始”标记之前,可以消除极端情况。

$ cat tst.awk
{
    beg[$1] = $6
    end[$1] = $7
    ids[++numIds] = $1
}
END {
    for (i=1; i<=numIds; i++) {
        idI = ids[i]
        for (j=1; j<=numIds; j++) {
            idJ = ids[j]
            if (idI != idJ) {
                if ( ( (beg[idI] >= beg[idJ]) && (beg[idI] <= end[idJ]) ) ||
                     ( (end[idI] >= beg[idJ]) && (end[idI] <= end[idJ]) ) ) {
                    if ( !seen[(idI<idJ ? idI FS idJ : idJ FS idI)]++ ) {
                        print idI, idJ
                    }
                }
            }
        }
    }
}

$ awk -f tst.awk file
id3 id4

您在问题中提供的输入文件不会涉及很多情况,因此,鉴于此输入文件包含更多重叠变量:

$ cat file
id1 185 403 . scaffold1 10  20
id2 185 403 . scaffold1 11  19
id3 185 403 . scaffold1  9  10
id4 185 403 . scaffold1 20  21
id5 185 403 . scaffold1  9  11
id6 185 403 . scaffold1 19  21
id7 185 403 . scaffold1 10  20
id8 185 403 . scaffold1  1   8

尝试上面的方法:

$ awk -f tst.awk file
id1 id3
id1 id4
id1 id5
id1 id6
id1 id7
id2 id1
id2 id5
id2 id6
id2 id7
id3 id5
id3 id7
id4 id6
id4 id7
id5 id7
id6 id7

与您在答案末尾提供的脚本+管道:

$ awk '{start[$1]=$6;stop[$1]=$7;} END {for(i in start) {for(j in stop) {if(start[i] >= start[j] && start[i] <= stop[j]) print i,j}}}' file | awk '{if($1!=$2) print}' -
id3 id5
id4 id6
id4 id7
id4 id1
id5 id3
id6 id7
id6 id1
id6 id2
id7 id3
id7 id5
id7 id1
id1 id3
id1 id5
id1 id7
id2 id5
id2 id7
id2 id1

并注意您的脚本两次报告了某些(但不是全部)ID之间的重叠:

id1 id7
id7 id1
id3 id5
id5 id3

而我的脚本仅在接受!seen[(idI<idJ ? idI FS idJ : idJ FS idI)]++才报告它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM