2013-01-12 45 views
1

我有這個輸入數據:如何分組相等的值並用Perl打印最小和最大參數?

miRNA17 dvex571195 207 230 
miRNA17 dvex571195 189 229 
miRNA17 dvex571195 207 241 
miRNA17 dvex571195 207 230 
miRNA17 dvex571195 80 111 
miRNA18 dvex449276 12 43 
miRNA18 dvex196735 2909 2929 
miRNA18 dvex765590 183 213 
miRNA22 dvex826214 206 236 
miRNA23 dvex529006 111 168 
miRNA24 dvex803612 317 347 

我想組相同的第一和第二個值的行。接下來,在這個「組」中,我需要在第三列中輸出「組」的最小值,在第四列中輸出「組」的最大值。輸出將是:

miRNA17 dvex571195 80 241 
miRNA18 dvex449276 12 43 
miRNA18 dvex196735 2909 2929 
miRNA18 dvex765590 183 213 
miRNA22 dvex826214 206 236 
miRNA23 dvex529006 111 168 
miRNA24 dvex803612 317 347 

我試圖將所有數據分組在一個大%哈希,我的密鑰由第一和第二列表示。但我可以使用一種方法來組織後繼列。該代碼是:

#!/usr/bin/perl 

use strict; 
use warnings; 
use Data::Dumper; 

my %lines; # hash with 1rd and 2th elements as key 
my %first_line_per_group; # stores in which line a group appeared first 
while(my $line = <>) { 
# remove line break 
chomp $line; 

# retrieve elements form line 
my @elements = split /\s+/, $line; 

# build key from elements 1 and 2 (array 0-based!) 
my $key = $elements[0]." ".$elements[1]; 

if(! $lines{key}) { 
    #my $min = max $elements[3]; 
    $first_line_per_group{$key} = $elements[0]."\t".$elements[1];#."\t".$min; 
} 
push @{ $lines{$key} }, $line; 

} 

# the result: 
for my $key (keys %lines) { 
    print $first_line_per_group{$key}."\t"; 
    print "$_\n" for @{ $lines{$key} }; 
} 

這段代碼的輸出是:

miRNA17 dvex571195 miRNA17 dvex571195 207 230 
miRNA17 dvex571195 189 229 
miRNA17 dvex571195 207 241 
miRNA17 dvex571195 207 230 
miRNA17 dvex571195 80 111 
miRNA18 dvex449276 miRNA18 dvex449276 12 43 
miRNA18 dvex196735 miRNA18 dvex196735 2909 2929 
miRNA18 dvex765590 miRNA18 dvex765590 183 213 
miRNA22 dvex826214 miRNA22 dvex826214 206 236 
miRNA23 dvex529006 miRNA23 dvex529006 111 168 
miRNA24 dvex803612 miRNA24 dvex803612 317 347 

但我需要消除分組值,並做上述工作。

+0

所需輸出保留由第一行順序;是故意的,還是將它分類是可以接受的? – ysth

回答

3

您只錯過了一件事:當$lines{key}爲真時,您想調整$first_line_per_group{$key},使其值包含組的最小值和最大值。

一些清理之後,你最終用下面的代碼:

my %groups; 
while (<>) { 
    my @f = split; 
    my $key = "$f[0] $f[1]"; 

    if ($groups{$key}) { 
     $f[2] = $groups{key}[2] if $groups{key}[2] < $f[2]; 
     $f[3] = $groups{key}[3] if $groups{key}[3] > $f[3]; 
    } 

    $groups{$key} = \@f; 
} 

for my $key (keys(%groups)) { 
    print(join(' ', @{ $groups{$key} }), "\n"); 
} 
+0

你在「一些清理後」提到什麼? –

+0

我不確定你在問什麼。也許我剛做的小編輯有幫助? – ikegami

+0

最後我明白了。解決方案非常棒。非常感謝!! –

1

你可能想看看這個程序,這似乎是你所需要的。

我不清楚你的文件是製表符分隔還是隻用空格分隔,但只要值中沒有空格就無關緊要。我已經把每個記錄分成了空格,因爲這就是你的代碼所做的。

use strict; 
use warnings; 

use List::Util qw/ min max /; 

my %data; 

while (<>) { 
    my @fields = split; 
    push @{ $data{"@fields[0,1]"} }, [ @fields[2,3] ]; 
} 

for my $key (sort keys %data) { 
    my $val = $data{$key}; 
    print join(' ', $key, min(map $_->[0], @$val), max(map $_->[1], @$val)), "\n"; 
} 

輸出

miRNA17 dvex571195 80 241 
miRNA18 dvex196735 2909 2929 
miRNA18 dvex449276 12 43 
miRNA18 dvex765590 183 213 
miRNA22 dvex826214 206 236 
miRNA23 dvex529006 111 168 
miRNA24 dvex803612 317 347 
相關問題