Дополнить шаблоны - PullRequest
       6

Дополнить шаблоны

1 голос
/ 05 января 2012

У меня есть такие записи в файле:

1867    121 2 56 
1868    121 1 6 
1868    121 2 65 
1868    122 0 53 
1869    121 0 41 
1869    121 1 41 
1871    121 1 13 
1871    121 2 194

Я хотел бы получить этот вывод:

1867    121 2 56 
1868    121 1 6 
1868    121 2 65 
1868    122 0 53 
1869    121 0 41 
1869    121 1 41 
1870    121 0 0
1871    121 1 13 
1871    121 2 194

Разница в строке 1870 121 0 0.

Итак, если разница между числами в первом столбце больше 1, то мы должны включить строку с пропущенным числом (в приведенном выше случае это 1870) и другие столбцы. Нужно получить другие столбцы таким образом, чтобы второй столбец был минимальным из возможных значений номеров столбцов (в примере эти значения могут быть 121 или 122), и для того же в случае третьего столбца. Значение последнего столбца пусть всегда будет нулевым.

Кто-нибудь может мне что-то подсказать? Заранее спасибо!

Я пытаюсь решить эту проблему с помощью awk, но, может быть, есть (есть) другие более хорошие или более практичные решения для этого ...

Ответы [ 4 ]

2 голосов
/ 05 января 2012

Примерно так может работать -

awk 'BEGIN{getline;a=$1;b=$2;c=$3}
NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next} 
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}' file file

Объяснение:

  1. BEGIN{getline;a=$1;b=$2;c=$3} -

    В этомBEGIN блок, мы читаем первую строку и присваиваем значения в column 1 переменной a, column 2 переменной b и column 3 переменной c.

  2. NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next} -

    При этом мы сканируем весь файл (NR==FNR) и отслеживаем минимально возможные значения в column 2 иcolumn 3 и сохраните их в переменных b и c соответственно.Мы используем next, чтобы избежать запуска второго оператора pattern{action}.

  3. {if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print} -

    Этот оператор action проверяет значение в column 1 и сравнивает его с a.Если разница больше 1, мы делаем for loop, чтобы добавить все пропущенные строки и установить значение a в $1.Если значение в column 1 в последовательных строках не превышает 1, мы присваиваем значение column 1 a и print it.

Тест:

[jaypal:~/Temp] cat file
1867    121 2 56 
1868    121 1 6 
1868    121 2 65 
1868    122 0 53 
1869    121 0 41 
1869    121 1 41 
1871    121 1 13  # <--- 1870 skipped
1871    121 2 194
1875    120 1 12 # <--- 1872, 1873, 1874 skipped

[jaypal:~/Temp] awk 'BEGIN{getline;a=$1;b=$2;c=$3}
NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next} 
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}' file file
1867    121 2 56 
1868    121 1 6 
1868    121 2 65 
1868    122 0 53 
1869    121 0 41 
1869    121 1 41 
1870    120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1871    121 1 13 
1871    121 2 194
1872    120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1873    120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1874    120 0 0 # Assigned minimum value in col 2 (120) and col 3 (0).
1875    120 1 12
1 голос
/ 05 января 2012

Решение Bash:

# initialize minimum of 2. and 3. column
read no min2 min3 c4 < "$infile"

# get minimum of 2. and 3. column
while read c1 c2 c3 c4 ; do
  [ $c2 -lt $min2 ] && min=$c2
  [ $c3 -lt $min3 ] && min=$c3
done < "$infile"

while read c1 c2 c3 c4 ; do
  # insert missing line(s) ?
  while (( c1- no > 1 )) ; do
    ((no++))
    echo -e "$no $min2 $min3 0"
  done
  # now insert existing line
  echo -e "$c1 $c2 $c3 $c4"
  no=$c1
done < "$infile"
1 голос
/ 05 января 2012

Perl решение. Должно работать и для больших файлов, так как не загружает весь файл в память, а просматривает файл два раза.

#!/usr/bin/perl
use warnings;
use strict;

my $file = shift;

open my $IN, '<', $file or die $!;

my @mins;
while (<$IN>) {
    my @cols = split;
    for (0, 1) {
        $mins[$_] = $cols[$_ + 1] if $cols[$_ + 1] < $mins[$_ ]
                                     or ! defined $mins[$_];
    }
}

seek $IN, 0, 0;
my $last;
while (<$IN>) {
    my @cols = split;
    $last //= $cols[0];

    for my $i ($last .. $cols[0]-2) {
        print $i + 1, "\t@mins 0\n";
    }
    print;
    $last = $cols[0];
}
0 голосов
/ 07 января 2012

В одну сторону, используя awk:

BEGIN { 
        if ( ARGC > 2 ) {
                print "Usage: awk -f script.awk <file-name>"
                exit 0
        }

        ## Need to process file twice, duplicate the input filename.
        ARGV[2] = ARGV[1]
        ++ARGC

        col2 = -1
        col3 = -1
}

## First processing of file. Get min values of second and third columns.
FNR == NR {
        col2 = col2 < 0 || col2 > $2 ? $2 : col2
        col3 = col3 < 0 || col3 > $3 ? $3 : col3
        next
}

## Second processing of file.
FNR < NR {
        ## Get value of column 1 in first row.
        if ( FNR == 1 ) {
                col1 = $1
                print
                next
        }

        ## Compare current value of column 1 with value of previous row.
        ## Add a new row while difference is bigger than '1'.
        while ( $1 - col1 > 1 ) {
                ++col1
                printf "%d\t%d %d %d\n", col1, col2, col3, 0
        }

        ## Assing new value of column 1.
        col1 = $1
        print
}

Запуск скрипта:

awk -f script.awk infile

Результат:

1867    121 2 56 
1868    121 1 6 
1868    121 2 65 
1868    122 0 53 
1869    121 0 41 
1869    121 1 41 
1870    121 0 0
1871    121 1 13 
1871    121 2 194
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...