簡體   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