Bash

提取兩個文件之間按順序交換的行的索引

  • May 30, 2022

我有兩個大的製表符分隔文件(>10GB),我知道當它們被排序時,它們的內容是相同的。

但是,當它們共享相同的“鍵”(此處的鍵被定義為基於SourceLocation列分組的行)時,我對行的順序和交換的索引感興趣。

換句話說,這兩個文件之間的行應該僅在它們來自同一組時(即它們共享相同的源和位置時)相互比較。

例如,在下面的範例中,第 4、5、6 行file1.tsv應該與第 4、5、6行進行比較file2.tsv

注意:文件是普通的 TSV。此處僅添加額外的空格以使列居中和右對齊,以獲得更好的可見性。這些空間不是原始文件的一部分

文件1.tsv

    Identifier  Position Source  Location
    AY1:2301        87    ch1        14
   BC1U:4010       105    ch1        14
   AC44:1230        90    ch1        15
   AJC:93410        83    ch1        16
   ABYY:0001       101    ch1        16
      ABC:01        42    ch1        16
     HH:A9CX       413    ch1        17
     LK:9310         2    ch1        17
   JFNE:3410       132    ch1        18
   MKASDL:11        14    ch1        18
  MKDFA:9401        18    ch1        18
 MKASDL1:011       184    ch2        50
  LKOC:AMC02        18    ch2        50
    POI:1100       900    ch2        53
   MCJE:09HA        11    ch2        53
  ABYCI:1123        15    ch2        53
    MNKA:410         1    ch2        53

文件2.tsv

    Identifier  Position Source  Location
    AY1:2301        87    ch1        14
   BC1U:4010       105    ch1        14
   AC44:1230        90    ch1        15
      ABC:01        42    ch1        16
   ABYY:0001       101    ch1        16
   AJC:93410        83    ch1        16
     HH:A9CX       413    ch1        17
     LK:9310         2    ch1        17
   MKASDL:11        14    ch1        18
   JFNE:3410       132    ch1        18
  MKDFA:9401        18    ch1        18
 MKASDL1:011       184    ch2        50
  LKOC:AMC02        18    ch2        50
    MNKA:410         1    ch2        53
    POI:1100       900    ch2        53
  ABYCI:1123        15    ch2        53
   MCJE:09HA        11    ch2        53

我想做類似於“差異”的事情,但在“組”級別(只有在它們共享相同Source和時才比較行Location

當行的順序在同一個“源/位置”“組”(或鍵)中“交換”時,我想提取原始的“行號” 。

整行應該在內容方面匹配。

但我不知道該怎麼做。當我的原始數據集有數百萬行時,我只能考慮編寫一個效率極低的 for 循環。

預期結果:

Group_Source:Location  df1.index  df2.index

ch1:16                         4          6
ch1:16                         6          4
ch1:18                         9         10
ch1:18                        10          9
ch2:53                        14         15
ch2:53                        15         17
ch2:53                        17         14

假設:

  • 兩個數據框的行數相同
  • 兩個數據幀是相同的(僅交換行的順序,因此如果兩者都按源排序,然後按位置排序,然後按位置排序,然後按標識符排序,那麼它們將完全相同)
  • “交換”的行總是在所有列的內容方面完全匹配

由於輸入文件的大小,這是我可能會使用的罕見情況之一,getline因此我們一次只在記憶體中保存幾行而不是> 10G:

$ cat tst.awk
BEGIN {
   OFS = "\t"
   print "Group_Source:Location", "df1.index", "df2.index"
}
NR != FNR { exit }
{ srcLoc = $3 ":" $4 }
srcLoc != prevSrcLoc {
   if ( NR > 1 ) {
       diff()
   }
   prevSrcLoc = srcLoc
}
{
   file1[$1,$2] = FNR - 1
   if ( (getline < ARGV[2]) > 0 ) {
       file2[$1,$2] = FNR - 1
   }
}
END { diff() }

function diff(          idPos) {
   for ( idPos in file1 ) {
       if ( file1[idPos] != file2[idPos] ) {
           print prevSrcLoc, file1[idPos], file2[idPos]
       }
   }
   delete file1
   delete file2
}
$ awk -f tst.awk file1.tsv file2.tsv
Group_Source:Location   df1.index       df2.index
ch1:16  6       4
ch1:16  4       6
ch1:18  10      9
ch1:18  9       10
ch2:53  17      14
ch2:53  15      17
ch2:53  14      15

有關更多資訊getline,請閱讀http://awk.freeshell.org/AllAboutGetline

即使在輸入中重複了Identifier和/或,上述內容也可以工作Position,因為它正在比較兩個文件之間的所有 4 個欄位。它確實假設 Source 和 Location 值在兩個文件之間的順序相同,如範例輸入中所示。

引用自:https://unix.stackexchange.com/questions/704362