Совпадение первых столбцов; прочитать шаблон и заменить указанными значениями c во втором столбце файла - PullRequest
0 голосов
/ 28 января 2020

Я хотел бы обновить файл1 (с разделителями табуляции), используя файл2 (с разделителями табуляции) условно.

Для каждой строки файла1 выполните следующие замены для каждого столбца, кроме первого, используя строку из file2, значение которого в первом столбце совпадает со значением строки file1 в первом столбце:

  • a . Если; поле в file1 содержит строку «A», замените ее строкой во втором столбце file2
  • b . иначе если; поле в file1 содержит строку «B», замените ее на строку в третьем столбце file2
  • c. еще; поле в файле1 со строкой "X", замените его строкой в ​​четвертом столбце файла2

Пожалуйста, помогите правильно добавить условия после сопоставления. Заранее спасибо.

awk 'FNR==NR{a[$1]=$1;next};{print a[$1]}'  file2.txt file1.txt>file3.txt

$ cat replace.awk
{
var1=$2;
var2=$3;
var3=$4;
if ( $0 == "A") $0=var1;
else if ( $0 == "B") $0=var2;
else $0=var3;
print $0,var1,var2,var3;
}

Входной файл1

ID  item1   item2   item3   item4 ..
592 A   B   X   B
598 A   B   X   A
612 A   X   A   X
650 A   X   A   B
700 A   X   A   B
822 A   X   A   A
830 A   X   A   A
840 A   X   A   X

Входной файл2

ID  var1    var2    var3
568 G   A   NA
570 T   C   NA
592 T   G   NA
598 A   T   NA
612 C   A   NA
650 C   T   NA
700 T   C   NA
822 T   C   NA
830 T   A   NA
840 G   C   NA
900 T   G   NA
1000    A   T   NA
....

Ожидаемый вывод

ID  item1   item2   item3   item4
592 T   G   NA  G
598 A   T   NA  A
612 C   NA  C   NA
650 C   NA  C   T
700 T   NA  T   C
822 T   NA  T   T
830 T   NA  T   T
840 G   NA  G   NA


Ответы [ 3 ]

3 голосов
/ 28 января 2020

С awk, пожалуйста, попробуйте следующее:

awk 'BEGIN {FS=OFS="\t"}
    FNR>1 && FNR==NR {a[$1,"A"]=$2; a[$1,"B"]=$3; a[$1,"X"]=$4; next}
    FNR==1 && FNR!=NR {print}
    FNR>1 {for (i=2; i<=5; i++) $i=a[$1,$i]
        print
    }
' file2.txt file1.txt

Вывод:

ID      item1   item2   item3   item4
592     T       G       NA      G
598     A       T       NA      A
612     C       NA      C       NA
650     C       NA      C       T
700     T       NA      T       C
822     T       NA      T       T
830     T       NA      T       T
840     G       NA      G       NA

[Объяснение]

  • При чтении file2 создается карта, связывающая base (A, G, T, C или NA) с конкатенацией ID (568 et c.) И item (A, B или X).
  • Печатает 1-ю строку file1 в виде строки заголовка.
  • При чтении file1 заменяет поля путем чтения ассоциативного массива, созданного в 1-м точка.

Надеюсь, это поможет.

2 голосов
/ 28 января 2020
perl -e'
    my %file2;
    {
       my $file2_qfn = shift(@ARGV);
       open(my $fh2, "<", $file2_qfn)
          or die("Can't open \"$file2_qfn\": $!\n");

       if (<$fh2>) {  # Skip header.
          while (<$fh2>) {
             chomp;
             my @fields = split /\t/;
             $file2{$fields[0]} = \@fields;
          }
       }
    }

    while (<>) {
       if ($. == 1) {  # Handle header.
          print;
          next;
       }

       chomp;
       my @fields = split /\t/;
       if ( my $changes = $file2{$fields[0]} ) {
          for (@fields[1..$#fields]) {
             if    ($_ eq "A") { $_ = $changes->[1]; }
             elsif ($_ eq "B") { $_ = $changes->[2]; }
             elsif ($_ eq "X") { $_ = $changes->[3]; }
          }
       }

       print(join("\t", @fields), "\n");
    }
' file2.tsv file1.tsv

Вышеуказанное загружает весь файл2 в память, но этого легко избежать, если два файла отсортированы по первому столбцу.

perl -e'
    sub get_row {
       my ($fh) = @_;
       defined( my $line = <$fh> )
          or return undef;

       chomp($line);
       return [ split /\t/, $line ];
    }

    sub print_row { print(join("\t", @_), "\n"); }

    my $file2_qfn = shift(@ARGV);
    open(my $fh2, "<", $file2_qfn)
       or die("Can't open \"$file2_qfn\": $!\n");

    my $fh1 = \*ARGV;

    my $row1 = get_row($fh1);
    if ($row1) {  # Handle header.
       print_row(@$row1);
       $row1 = get_row($fh1);
    }

    my $row2 = get_row($fh2);
    $row2 = get_row($fh2) if $row2;  # Skip header.

    while ($row1 && $row2) {
       my $cmp = $row1->[0] <=> $row2->[0];
       if ($cmp <= 0) {
          if ($cmp == 0) {
             for (@$row1[1..$#$row1]) {
                if    ($_ eq "A") { $_ = $row2->[1]; }
                elsif ($_ eq "B") { $_ = $row2->[2]; }
                elsif ($_ eq "X") { $_ = $row2->[3]; }
             }
          }

          print_row(@$row1);
       }

       $row1 = get_row($fh1) if $cmp <= 0;
       $row2 = get_row($fh2) if $cmp >= 0;
    }

    while ($row1) {
       print_row(@$row1);
       $row1 = get_row($fh1);
    }
' file2.tsv file1.tsv

Использование (обе версии):

perl -e'...' -i~ file2.tsv file1.tsv        # Modifies named file in place with backup.
perl -e'...' -i file2.tsv file1.tsv         # Modifies named file in place without backup.
perl -e'...' file2.tsv file1.tsv >out.tsv   # Reads from named file, outputs to STDOUT.
1 голос
/ 28 января 2020

Пожалуйста, смотрите код для объяснения

#!/usr/bin/perl
#
# USAGE:
#   prog.pl -a fileA -b fileB
#
# Description:
#   Demonstration code for StackOverflow Q59942022
#
# Parameters:
#   -a,--filea  input file with pattern to substitudes
#   -b,--fileb  input file with values for substitution
#   -d,--debug  debug flag
#   -h,--help   brief help message
#   --man       manual page with more details
#
# StackOverflow: 
#   Question 59942022
#
# Author:
#   Polar Bear
#
# Date: Tue Jan 28 3:09:00 PST 2020
#

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

use Getopt::Long qw(GetOptions);
use Pod::Usage;
use Data::Dumper;

my $debug = 0;

my $fh;         # file handler
my %opt;        # command line options
my %data;       # fileA data storage
my %fileb;      # fileB data storage
my @order;      # to keep line order

GetOptions(
        'filea|a=s'     => \$opt{data},
        'fileb|b=s'     => \$opt{fileb},
        'debug|d'       => \$opt{debug},
        'help|?'        => \$opt{help},
        'man'           => \$opt{man}
) or pod2usage(2);

pod2usage(1) if $opt{help};
pod2usage(-exitval => 0, -verbose => 2) if $opt{man};

print Dumper(\%opt) if $opt{debug};

open $fh, '<', $opt{data}
        or die "Couldn't open $opt{data}";

map {                                   # process fileA (pattern)
    chomp;
    my @a = split /\t/; 
    push @order, $a[0];                 # preserve line order
    push @{$data{$a[0]}}, @a[1..$#a]
} <$fh>;

close $fh;

open $fh, '<', $opt{fileb}
        or die "Couldn't open $opt{fileb}";

map {                                   # process fileB (values)
    chomp;
    my @a = split /\t/;
    push @{$fileb{$a[0]}}, @a[1..$#a];
} <$fh>;

close $fh;

say Dumper(\%data)  if $debug;
say Dumper(\%fileb) if $debug;

foreach my $k ( @order ) {              # make required substitution
    if( defined $fileb{$k} ) {
        foreach my $i (0..$#{$data{$k}}) {
            $data{$k}[$i] = $fileb{$k}[0] if $data{$k}[$i] eq 'A';
            $data{$k}[$i] = $fileb{$k}[1] if $data{$k}[$i] eq 'B';
            $data{$k}[$i] = $fileb{$k}[2] if $data{$k}[$i] eq 'X';
        }
    }
    say join "\t", $k, @{$data{$k}};    # output result to console
} 

__END__

=head1 NAME

program - describe program's functionality 

=head1 SYNOPSIS

program.pl [options]

 Options:
    -a,--filea  fileA input filename
    -b,--fileb  fileB input filename
    -d,--debug  output debug information
    -?,--help   brief help message
       --man    full documentation

=head1 OPTIONS

=over 4

=item B<-a,--filea>

FileA input filename

=item B<-b,--fileb>

FileB input filename

=item B<-d,--debug>

Print debug information.

=item B<-?,--help>

Print a brief help message and exits.

=item B<--man>

Prints the manual page and exits.

=back

B<This program> reads two input files and substitudes values in first file
according predefined rules: A - second column, B - third column, X - forth column

=cut

Входной файл A

ID  item1   item2   item3   item4 ..
592 A   B   X   B
598 A   B   X   A
612 A   X   A   X
650 A   X   A   B
700 A   X   A   B
822 A   X   A   A
830 A   X   A   A
840 A   X   A   X

Входной файлB

ID  var1    var2    var3
568 G   A   NA
570 T   C   NA
592 T   G   NA
598 A   T   NA
612 C   A   NA
650 C   T   NA
700 T   C   NA
822 T   C   NA
830 T   A   NA
840 G   C   NA
900 T   G   NA
1000    A   T   NA

Выход

ID      item1   item2   item3   item4 ..
592     T       G       NA      G
598     A       T       NA      A
612     C       NA      C       NA
650     C       NA      C       T
700     T       NA      T       C
822     T       NA      T       T
830     T       NA      T       T
840     G       NA      G       NA
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...