1

我想找到一个所有值都大于 0.3 的连续范围。例如

A   1   10  0.2
A   20  40  0.4
A   60  75  0.5
A   90  100 0.55
A   200 205 0.43
A   211 270 0.8
A   450 511 0.1
A   513 550 0.0
B   1   10  0.6
B   50  200 0.7
B   300 350 0.8
B   400 500 0.9
B   600 711 0.4
B   800 900 0.2

输出:

A   20  270
B   1   711

我试过了:

while(<>){
        chomp($_);
        my @line = split("\t| ", $_);
        my $letter=$line[0];
        my @start;
        my @end;
                if($line[3]>0.3){
                        push (@start, $line[1]);
                        push (@end, $line[2]);

                        }
                if($line[3]<0.3){
                        next;}
                print $letter,"\t",$start[0],"\t",$end[-1],"\n";
                }

但我得到:

A       20      40
A       60      75
A       90      100
A       200     205
A       211     270
B       1       10
B       50      200
B       300     350
B       400     500
B       600     711

但我只想要每个适当范围的第一个开始和最后一个结束

4

2 回答 2

3

你没有说你想要第一个还是最后一个字母(或者如果你想把一个字母改变当作结束一个范围),所以我只做第一个。

my $in_range;
my @ranges;
while (<>) {
    chomp;
    my ($letter, $start, $end, $value) = split /\t| /, $_;
    if ($value <= .3) {
        $in_range = undef;
    }
    elsif ($in_range) {
        $in_range->{'end'} = $end;
        push @{ $in_range->{'values'} }, $value;
    }
    else {
        $in_range = {
            'letter' => $letter,
            'start' => $start,
            'end' => $end,
            'values' => [ $value ],
        };
        push @ranges, $in_range;
    }
}

for my $range (@ranges) {
    print join( "\t",
        @$range{ qw/letter start end/ },
        scalar( @{ $range->{'values'} } ),
        join( ',', @{ $range->{'values'} } )
    ), "\n";
}

(根据评论更新以显示值)

于 2013-09-29T16:08:08.027 回答
1

使用哈希怎么样?

#!/usr/bin/perl

use strict;
use warnings;

my %values;
while (<>) {
    chomp;
    my ($letter, $start, $end, $val) = split "\t| ";

    next if (defined $values{$letter}{skip_rest});

    if ($val > 0.3) {
        $values{$letter}{min} = $start
            if not defined $values{$letter}{min} or $values{$letter}{min} > $start;
        $values{$letter}{max} = $end
            if not defined $values{$letter}{max} or $values{$letter}{max} < $end;
    }
    elsif (defined $values{$letter}{min} and defined $values{$letter}{max}) {
        $values{$letter}{skip_rest} = "true";
    }
}

foreach my $letter (sort keys %values) {
    print "$letter\t$values{$letter}{min}\t$values{$letter}{max}\n";
}
于 2013-09-29T16:25:12.723 回答