2012-02-27 71 views
0

我有3列的文件 - >以只形成連續範圍的值

 
A1 0 9 
A1 4 14 
A1 16 24 
A1 25 54 
A1 64 84 
A1 74 84 
A2 15 20 
A2 19 50

我要檢查,如果每一行(在COL2值和3)是目前已經或正在的範圍之間上一行,如果col1值相等。 所需的輸出是 - >

 
A1 0 14 
A1 16 54 
A1 64 84 
A2 15 50 

我曾嘗試 - >

@ARGV or die "No input file specified"; 
open $first, '<',$ARGV[0] or die "Unable to open input file: $!"; 
#open $second,'<', $ARGV[1] or die "Unable to open input file: $!"; 
$k=0; 
while (<$first>) 
{ 
if($k==0) 
{ 
@cols = split /\s+/; 
$p0=$cols[0]; 
$p1=$cols[1]; 
$p2=$cols[2]; 
$p3=$cols[2]+1; 
} 

else{ 
@new = split /\s+/; 
if ($new[0] eq $p0){ 
    if ($new[1]>$p3) 
     { 
    print join("\t", @new),"\n"; 
    $p0=$new[0]; 
    $p1=$new[1]; 
    $p2=$new[2]; 
    $p3=$new[2]+1; 


     } 
    elsif ($new[2]>=$p2) 
    { 
    print $p0,"\t",$p1,"\t",$new[2],"\n"; 
    $p2=$new[2]; 
    $p3=$new[2]+1; 
    } 

    else 
     { 
    $p5=1; 

     } 
} 

     else 
     { 
    print join("\t", @new),"\n"; 
     $p0=$new[0]; 
    $p1=$new[1]; 
    $p2=$new[2]; 
    $p3=$new[2]+1; 

     }} 
     $k=1; 

} 

和我得到的輸出 - >

A1 0  14 
A1 16  24 
A1 16  54 
A1 64  84 
A1 64  84 
A2 15  20 
A2 22  50

我無法理解爲什麼我得到這個錯誤的輸出。此外,如果有任何方法可以擦除(或覆蓋)最後打印的行,那麼這將非常容易。

+0

使用一個:http://p3rl.org/News::Newsrc http://p3rl.org/Number: :Interval http://p3rl.org/Parse::Range http://p3rl.org/Set::IntSpan [:: Fast](http://p3rl.org/Set::IntSpan::Fast)[: :XS](http://p3rl.org/Set::IntSpan::Fast::XS) – daxim 2012-02-27 14:17:36

回答

2

首先,它會更簡單,以幫助你,如果你

  • 使用strictwarnings,並宣佈所有variabled接近第一次使用與my
  • 縮進你的代碼正確顯示結構

您的代碼失敗的原因是您在太多條件下打印數據。例如,你的輸出A1 16 24當你發現它不能與先前範圍A1 4 14,而無需等待它通過後續A1 25 54擴展(當你正確地擴大覆蓋範圍,並再次打印)加盟。 A1 64 84是出於同樣的原因輸出兩次:第一次是因爲它不能與A1 25 54合併,並再次因爲它已經被「擴展」與A1 74 84。最後A2 15 20會立即輸出,因爲它具有新的第一列,即使它與下一行合併並再次輸出。

你需要輸出範圍只有當你發現它不能再次延長。當這種情況發生

  • 一個新的記錄發現,不重疊現有數據
  • 達到

此代碼打印輸出只有在一個被用來做這些情況下,文件的末尾你需要什麼。

use strict; 
use warnings; 

my @data; 

while (<DATA>) { 

    if (not @data) { 
    @data = split; 
    next; 
    } 

    my @new = split; 

    if ($new[0] eq $data[0] and $new[1] <= $data[2] + 1) { 
    $data[2] = $new[2]; 
    } 
    else { 
    print join("\t", @data), "\n"; 
    @data = @new; 
    } 

    print join("\t", @data), "\n" if eof DATA; 

} 

__DATA__ 
A1 0 9 
A1 4 14 
A1 16 24 
A1 25 54 
A1 52 57 
A1 59 62 
A1 64 84 
A1 74 84 
A2 15 20 
A2 19 50 

OUTPUT

各種跨度/範圍/間隔模塊
A1 0 14 
A1 16 57 
A1 59 62 
A1 64 84 
A2 15 50 
+0

感謝您的回覆。下一次,我肯定會發布我的代碼結構良好。對不起,只是一個新手,並試圖學習。另外,我認爲,有人已經編輯了你的答案,因爲現在if和else的條件已經交換,這是行不通的。 – Vikas 2012-02-27 15:58:28

+0

因爲我更喜歡那種方式,所以我改變了「if」語句以及測試的感覺。它仍然正常工作。 – Borodin 2012-02-27 16:57:18

+0

對不起,我的錯。它的工作。 – Vikas 2012-02-27 17:14:31

0

您需要有一些描述當前累積連續區域的變量。對於每一行輸入,如果新輸入是新的column1標籤,或者是相同的標籤但不連續,或者是文件結束,則刷新先前累積的區域。如果它是相同的標籤,並連續喲更新最小值和最大值。

這假定列1和2進行排序。

其餘的就留給讀者自己練習。

+0

感謝您的回覆。在我的代碼中,如果第1列值是新的,我會直接打印。我正在使用這些變量($ p0,p1,p2,p3)來存儲最後的值,以便我可以將它們與新的值進行比較,但結果並非如我期待的那樣出現,並且我無法在此找到錯誤。你能否給我建議,我在代碼中犯了什麼錯誤? – Vikas 2012-02-27 14:10:18