Как создать таблицу на основе координат в perl? - PullRequest
0 голосов
/ 22 февраля 2020

У меня есть большой файл, содержащий количество точек, позицию и набор координат, например:.

no  pos/neg cordinates
1     +     1    3
2     +     5    8
3     -    10   12

Что я хочу сделать, это сначала преобразовать длину интервалов в точку (1 От -3 -> до 1 2 3) далее в новом столбце каждый раз, когда у меня есть (+), добавить 1, -1, когда у меня есть (-), и ноль 0, когда я нахожусь вне координаты, и в другом столбце, чтобы получим сумму во втором столбце, как в таблице ниже иметь дело с этим. Вначале я думал об использовании командной строки для генерации 3 файлов, а затем paste их, как в одном, но возникли технические трудности.

Например, с помощью sed 1 12 я могу сгенерировать первый столбец, но не могу использовать sed для связывания 2ond и 3-го, даже если знаю, как их вычислить

awk 'BEGIN {v=0} {if ($2=="-") {v=v-1} else {v=v+1}; $4=v; print}'
    | awk '{print $0 "\t" (c+=$4"1")}'

Это не несессери использовать perl, поэтому, если кто-нибудь знает, как связать эти команды, я буду обязан.

Ответы [ 2 ]

3 голосов
/ 22 февраля 2020

[ Существует несоответствие между заявленным желаемым выходом OP (10 -1 -6) и выводом, произведенным предоставленным кодом awk (10 -1 6). В этом ответе предполагается, что OP хочет, чтобы вывод производился с помощью предоставленного кода awk. ]

#!/usr/bin/perl

use strict;
use warnings;
use feature qw( say );

my %incs_by_sign = ( "+" => 1, "-" => -1 );

# Skip header.
defined(scalar(<>))
   or exit;

my $val = 0;
my $i;
while (<>) {
   my (undef, $sign, $x, $y) = split;

   if (defined($i)) {
      # Backfill the gap.
      for (; $i<$x; ++$i) {
         say join "\t", $i, 0, $val;
      }
   } else {
      $i = $x;
   }

   # Flatten.
   my $inc = $incs_by_sign{$sign};
   for (; $i<=$y; ++$i) {
      $val += $inc;
      say join "\t", $i, $inc, $val;
   }
}

В качестве сжатого "однострочного":

perl -lane'
   BEGIN { $, = "\t"; }
   next if $. == 1;  # Skip header.
   $i //= $F[2];
   print $i++, 0, $val while $i < $F[2];
   my $inc = 0 + ( $F[1] . 1 );
   print $i++, $inc, $val += $inc while $i <= $F[3];
'

Выход:

1       1       1
2       1       2
3       1       3
4       0       3
5       1       4
6       1       5
7       1       6
8       1       7
9       0       7
10      -1      6
11      -1      5
12      -1      4

Оба решения предполагают, что входной файл отсортирован по координатам.

И сценарий, и однострочный принимают входные данные из файла, названного его параметром, или из STDIN, если параметров нет предоставляются.

0 голосов
/ 22 февраля 2020

Следующий код читает данные, пропускает заголовок, разделяет строку на пробелы, определяет значение приращения и вычисляет сумму

use strict;
use warnings;
use feature 'say';

my $sum   = 0;                          # sum 
my $count = 1;                          # line counter

while(<DATA>){                          # read data
    next if /pos/;                      # skip header
    my($n,$p,$a,$b) = split '\s+';      # split on spaces

    say $_ . "\t0\t$sum" for $count..$a-1; # gap block

    my $i;                              # '+'/'-' increment
    $i =  1 if $p eq '+';               # incremet  by  1 if '+'
    $i = -1 if $p eq '-';               # decrement by -1 if '-'

    for ($a..$b) {                      # pos point coordinates
        $sum += $i;                     # calculate sum
        say "$_\t$i\t$sum";             # output
    }
    $count=$b+1;                        # increment counter for next line
}

__DATA__
no  pos/neg cordinates
1     +     1    3
2     +     5    8
3     -    10   12

Выход

1       1       1
2       1       2
3       1       3
4       0       3
5       1       4
6       1       5
7       1       6
8       1       7
9       0       7
10      -1      6
11      -1      5
12      -1      4
...