Как я могу определить, в какие диапазоны попадает данное значение? - PullRequest
1 голос
/ 24 августа 2011

У меня есть два набора данных: «Данные 1» и «Данные 2».Не могли бы вы помочь мне найти для каждого значения posi в «Data 1» диапазоны в «Data 2», где posi находится между Star_posi и end_posi.

Data 1

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

Данные 2

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

Вывод

  1. Данные 1 в позиции 2, содержащиеся в данных 2 между star_posi 1 и end_posi 10.
  2. Данные 1 в позиции 14, содержащиесяв данных 2 между star_posi 3 и end_posi 15.

Я хочу идентифицировать строки в данных 2, где значение в данных 1 содержится в диапазоне строк в данных 2. Я создал скриптниже, но я не ушел далеко.

   #!/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); 

Буду признателен, если вы дадите несколько указателей.

Ответы [ 2 ]

3 голосов
/ 24 августа 2011

Ваш код - беспорядок.Кроме того, это никак не решает вашу проблему.

То, что вы хотите сделать, - это split строки из файла в цикле while, сохраняя их в хэше.Получив значения, вы можете легко сравнить их с операторами < и >, чтобы увидеть, в какие диапазоны они попадают.

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;

Обратите внимание, что я пропускаю (next) любые строкикоторые не начинаются с цифр, например, заголовков и пустых строк и других вещей, которые нам не нужны в данных.

Теперь у вас будут значения в хешах, и вы сможете выполнять любые необходимые вам тесты.Например:

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;
        }
    }
}

Удачи!

2 голосов
/ 24 августа 2011

Вы должны взглянуть на модуль CPAN с именем Tie :: RangeHash , который предназначен для точно такого рода проблемы.

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";
...