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

Linux 使用awk打印两列之间具有重叠值范围的记录对,linux,bash,unix,awk,Linux,Bash,Unix,Awk,我有不同的记录,对应于开始($6)和停止($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的范

我有不同的记录,对应于开始($6)和停止($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]此解决方案需要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];
            }
        }
    }
}

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

此解决方案需要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 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
试试上面的方法:

$ 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
vs您在回答结束时提供的脚本+管道:

$ 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
而我的脚本只报告了一次,这要归功于
!seen[(idI
试试上面的方法:

$ 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
vs您在回答结束时提供的脚本+管道:

$ 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


而我的脚本只报告了一次,这是
!seen[(i祝您好运。请您的问题显示您遇到问题的代码的一部分,然后我们可以尝试帮助您解决具体问题。您还应该阅读。暴力强制执行实际上非常简单。将开始和停止数据读取到由
id
列索引的关联数组中,然后检查所有可能的i对只需谷歌重叠间隔或类似的东西。@MichaelVehrs:True,但如果数字或记录很大,则处理时间(和内存)可能会爆炸。有多少条记录包含该文件?@casimirithippolyte大约1500条记录…祝你好运。请你的问题显示你遇到问题的代码的一部分,然后我们可以尝试帮助解决具体问题。你还应该阅读。暴力强制这其实很容易。将开始和停止数据读入asso由
id
列索引的活动数组,然后检查所有可能的id对。只需搜索重叠间隔或类似的内容。@MichaelVehrs:True,但如果数量或记录较大,则处理时间(和内存)可能会爆炸。有多少条记录包含该文件?@casimirithippolyte大约1500条记录…这些记录报告在没有记录的地方重叠,并且遗漏了一些确实存在的记录。请针对我添加到的示例输入文件进行尝试。它们在我提到的示例中是唯一的。哦,等等。索引指的是开始和停止值,而不是st处的实际id值每一行的艺术。好吧,那么…@EdMorton是的,这就是我的意思。事实上,多走一英里并不难。听起来不错。我个人无法理解逻辑,但可能只是我自己,我没有花太多时间在其中…报告重叠的地方没有,遗漏了一些确实存在的地方。试着对照sa我添加到的示例输入文件。它们在我提到的示例中是唯一的。哦,等等。索引指的是开始值和停止值,而不是每行开始处的实际id值。好吧,那么…@EdMorton是的,这就是我的意思。事实上,多走一英里并不难。听起来不错。我个人无法理解逻辑,但它是正确的可能只有我一个人,我没有花太多时间在这上面…非常感谢你的建议!非常感谢你的建议!