开发者

How can I identify which ranges a given value falls in?

I have two data sets: 'Data 1' and 'Data 2'. Could you please help me to find, for each value of posi in 'Data 1', the ranges in 'Data 2开发者_如何学JAVA' where posi lies between Star_posi and end_posi.

Data 1

  Num     posi 
   1        2 
   2        14
   3        18
   4        19
  ...      ...

Data 2

 Num      Star_posi    End_posi
  1          1            10
  2          3            15
  3          17           21
  4          23           34
 ...       ...           ...

Output

  1. Data 1 at posi 2 contained in Data 2 between star_posi 1 and end_posi 10.
  2. Data 1 at posi 14 contained in Data 2 between star_posi 3 and end_posi 15.

I want to identify the rows in Data 2 where the value in Data 1 is contained in the range of the row in Data 2. I made the script below, but I did not get far.

   #!/usr/bin/perl -w
   use strict;
   use warnings;
   use Data:ump qw(dump);

   #Sort the position**************

   my (@posi1, $Num2, @Num2, @Num1);
   open(POS1,"<posi.txt");
   @posi1=<POS1>;
   @Num1=@posi1;
   open(LIST,">list.txt"); {
   @Num2= sort {$a <=> $b} @Num1;
   $Num2 = join( '', @Num2);
   print $Num2;
   print LIST $Num2."\n";
   }
   close(LIST); 

I would appreciate if you could give some pointers.`


Your code is a mess. Also, it does not address your problem in any way.

What you want to do is split the lines from the file in a while loop, storing them in a hash. Once you have the values, you can easily compare them with the < and > operators to see in what ranges they fall.

use strict;
use warnings;
use autodie;

my (%data1,%data2);


open my $in, '<', 'data1.txt';
while (<$in>) {
    next unless /^\s*\d/;
    my ($num, $posi) = split;
    $data1{$num} = $posi;
}

open $in, '<', 'data2.txt';
while (<$in>) {
    next unless /^\s*\d/;
    my ($num, $star, $end) = split;
    $data2{$num}{'star'} = $star;
    $data2{$num}{'end'}  = $end;
}
close $in;

Note that I am skipping (next) any lines which do not start with numbers, e.g. headers and empty lines and other stuff we don't want in the data.

Now you will have the values in the hashes, and can perform what tests you need. For example:

for my $num (keys %data1) {
    my $val = $data1{$num};
    for my $num2 (keys %data2) {
        my $min = $data2{$num2}{'star'};
        my $max = $data2{$num2}{'end'};
        if ( ($val > $min) and ($val < $max) ) {
            print "Data 1 at posi $val contained in Data 2 between star_posi $min and end_posi $max.\n";
            last;
        }
    }
}

Good luck!


You should have a look at the CPAN module called Tie::RangeHash, which is for exactly this sort of problem.

use Tie::RangeHash;
my $hour_name = new Tie::RangeHash Type => Tie::RangeHash::TYPE_NUMBER;

$hour_name->add(' 0, 5', 'EARLY');
$hour_name->add(' 6,11', 'MORNING');
$hour_name->add('12,17', 'AFTERNOON');
$hour_name->add('18,23', 'EVENING');

# and in a loop elsewhere...
my $name = $hour_name->fetch($hour) || "UNKNOWN";
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜