2010-08-18 54 views
1

所以我的數據樣本採用以下格式。需要比較第一列重複的文件中的值

jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 19856 19974 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 21455 21638 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 21727 21897 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 21980 22063 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 24670 24811 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 34741 34902 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 3649 3836 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 59253 59409 
jgi|Xentr4|100173|gw1.779.90.1 scaffold_779 101746 101969 
jgi|Xentr4|100173|gw1.779.90.1 scaffold_779 106436 107233 

什麼,我試圖做的是在第一列的每個唯一的名稱,檢索列3分鐘值,併爲第4列的最大值所以最後輸入看起來一樣的,製表符分隔的文件,除了每個唯一名稱具有前2列以外,第3列和第4列是上述最小值和最大值。我在編程方面相當新手,並嘗試使用哈希來做到這一點,但失敗了。現在正在嘗試數組/正則表達式,如下所示。

open (IN, "POS2") || die "nope\n"; 
my $prev_qn = super; 
my $prev_sn = ultra; 
my $prev_start = non; 
my $prev_end = nono; 
while (<IN>) { 
    chomp; 
    push (@list, "$_"); 
} 
close (IN); 
foreach $v (@list) { 
    $info = $v; 
    ($query_name, $scaf_num, $start, $end) = split(/\t/, $info); 
    unless ($info =~ m/^$prev_qn/) { 
     push @ready, $info; 
     $prev_qn = $query_name; 
     $prev_sn = $scaf_num; 
     $prev_start = $start; 
     $prev_end = $end; 
    } 
    else { 
     if ($start < $prev_start) { 
      splice(@ready,2,1,$start); 
     } 
     if ($end > $prev_end) { 
      splice(@ready,3,1,$end); 
     } 
     $prev_qn = $query_name; 
     $prev_sn = $scaf_num; 
     $prev_start = $start; 
     $prev_end = $end; 
    } 

    foreach $z (@ready) { 
     print "$z\n"; 
    } 
} 

該返回的輸出如下所示。

jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
21638 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
21638 
21897 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
21638 
22063 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
21638 
24811 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
21638 
34902 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
3649 
34902 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
3649 
59409 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 18150 18354 
19974 
3649 
101969 

所以它似乎很清楚,該文件是做的比較細,但不更換數組中的元素如預期,只是追加他們腳下的和更換的。此外,它從不打印超過第一個唯一的名稱。有什麼建議麼?

回答

0

這是做你在找什麼?

open (IN, "POS2") || die "nope\n"; 
my %data; 

# Read data line by line 
while (<IN>) 
{ 
    chomp; 
    my @fields = split /\t/; 

    # Note $fields[0] is the name by which we want to group. 
    if (defined $data{$fields[0]}) 
    { 
     # If there is already an entry for this name, update it 
     $data{$fields[0]} = [ 
      $fields[1], 
      $data{$fields[0]}[1] < $fields[2] ? $data{$fields[0]}[1] : $fields[2], 
      $data{$fields[0]}[2] > $fields[3] ? $data{$fields[0]}[2] : $fields[3] 
     ]; 
    } 
    else 
    { 
     # Otherwise, create a new one 
     $data{$fields[0]} = [ $fields[1], $fields[2], $fields[3] ]; 
    } 
} 
close (IN); 

# Output one row for each group 
foreach my $name (keys %data) 
{ 
    my ($stuff, $min, $max) = @{$data{$name}}; 
    print "$name\t$stuff\t$min\t$max\n"; 
} 

我嘗試這樣做,它輸出這樣的:

jgi|Xentr4|100173|gw1.779.90.1 scaffold_779 101746 107233 
jgi|Xentr4|100164|gw1.1441.2.1 scaffold_1441 3649 59409 

這是你想要的嗎?

+0

兩個那些爲我工作,謝謝你們這麼多,我曾試過之前的散列策略卻陷入了語法困境,所以這些腳本也將幫助我學習如何更好地設置事物 – Adam 2010-08-18 23:15:48

1

以下是一種方法。只需提供輸入文件名作爲命令行參數即可。 <>操作員將打開文件並將腳本提供給腳本。

use strict; 
use warnings; 

my %h; 

while (my $line = <>){ 
    chomp $line; 
    my ($k, $scaff, $mn, $mx) = split /\t/, $line; 

    $h{$k} = { min => 9e99, max => -9e99 } unless exists $h{$k}; 

    $h{$k}{min} = $mn if $mn < $h{$k}{min}; 
    $h{$k}{max} = $mx if $mx > $h{$k}{max}; 
} 

for my $k (sort keys %h){ 
    print join("\t", $k, $h{$k}{min}, $h{$k}{max}), "\n"; 
} 

我使用了哈希的哈希值來存儲最小和最大的信息,因爲它使代碼更聲明,並因爲它的靈活。例如,假設您決定輸出需要保留列1中第一次出現任何名稱的順序。只要首次出現名稱,只需將其他元素添加到哈希散列結構中以跟蹤輸入行號:

$h{$k} = { min => 9e99, max => -9e99, line_n => $. } unless exists $h{$k}; 

然後使用新的一塊信息排序輸出時:

for my $k (sort { $h{$a}{line_n} <=> $h{$b}{line_n} } keys %h){ 
    # Same as above. 
} 
0

能做到以下幾點:

use FileHandle; 

$file = new FileHandle "input_file"; 
@array = <$file>; 
close $file; 

%seen =(); 

foreach (@array){ 
    ($col1,$col2,$col3,$col4) = split(/[\t\s]+/,$_); 
    push(@newarray,$_) unless $seen{$col1}++; 
} 
print @newarray; 
相關問題