fusionar dos archivos con columnas similares
Frecuentes
Visto 1,064 veces
0
Tengo dos archivos separados por pestañas que necesito alinear juntos. por ejemplo:
File 1: File 2:
AAA 123 BBB 345
BBB 345 CCC 333
CCC 333 DDD 444
(¡Estos son archivos grandes, potencialmente miles de líneas!)
Lo que me gustaría hacer es que la salida se vea así:
AAA 123
BBB 345 BBB 345
CCC 333 CCC 333
DDD 444
Preferiblemente me gustaría hacer esto en perl, pero no estoy seguro de cómo. Cualquier ayuda seria grandemente apreciada.
4 Respuestas
1
Si solo se trata de hacer una estructura de datos, esto puede ser bastante fácil.
#!/usr/bin/env perl
# usage: script.pl file1 file2 ...
use strict;
use warnings;
my %data;
while (<>) {
chomp;
my ($key, $value) = split;
push @{$data{$key}}, $value;
}
use Data::Dumper;
print Dumper \%data;
A continuación, puede generar en cualquier formato que desee. Si realmente se trata de usar los archivos exactamente como son, entonces es un poco más complicado.
contestado el 03 de mayo de 12 a las 21:05
0
Suponiendo que los archivos están ordenados,
sub get {
my ($fh) = @_;
my $line = <$fh>;
return () if !defined($line);
return split(' ', $line);
}
my ($key1, $val1) = get($fh1);
my ($key2, $val2) = get($fh2);
while (defined($key1) && defined($key2)) {
if ($key1 lt $key2) {
print(join("\t", $key1, $val1), "\n");
($key1, $val1) = get($fh1);
}
elsif ($key1 gt $key2) {
print(join("\t", '', '', $key2, $val2), "\n");
($key2, $val2) = get($fh2);
}
else {
print(join("\t", $key1, $val1, $key2, $val2), "\n");
($key1, $val1) = get($fh1);
($key2, $val2) = get($fh2);
}
}
while (defined($key1)) {
print(join("\t", $key1, $val1), "\n");
($key1, $val1) = get($fh1);
}
while (defined($key2)) {
print(join("\t", '', '', $key1, $val1), "\n");
($key2, $val2) = get($fh2);
}
contestado el 03 de mayo de 12 a las 20:05
0
Similar a la respuesta de Joel Berger, pero este enfoque le permite realizar un seguimiento de si los archivos contenían o no una clave determinada:
my %data;
while (my $line = <>){
chomp $line;
my ($k) = $line =~ /^(\S+)/;
$data{$k}{line} = $line;
$data{$k}{$ARGV} = 1;
}
use Data::Dumper;
print Dumper(\%data);
Salida:
$VAR1 = {
'CCC' => {
'other.dat' => 1,
'data.dat' => 1,
'line' => 'CCC 333'
},
'BBB' => {
'other.dat' => 1,
'data.dat' => 1,
'line' => 'BBB 345'
},
'DDD' => {
'other.dat' => 1,
'line' => 'DDD 444'
},
'AAA' => {
'data.dat' => 1,
'line' => 'AAA 123'
}
};
contestado el 03 de mayo de 12 a las 21:05
0
Como mencionó ikegami, se supone que el contenido de los archivos está organizado como se muestra en su ejemplo.
use strict;
use warnings;
open my $file1, '<file1.txt' or die $!;
open my $file2, '<file2.txt' or die $!;
my $file1_line = <$file1>;
print $file1_line;
while ( my $file2_line = <$file2> ) {
if( defined( $file1_line = <$file1> ) ) {
chomp $file1_line;
print $file1_line;
}
my $tabs = $file1_line ? "\t" : "\t\t";
print "$tabs$file2_line";
}
close $file1;
close $file2;
Al revisar su ejemplo, muestra algunos pares clave/valor idénticos en ambos archivos. Dado esto, parece que desea mostrar los pares exclusivos del archivo 1, exclusivos del archivo 2 y mostrar los pares comunes. Si este es el caso (y no está tratando de hacer coincidir los pares de archivos por claves o valores), puede use List::Compare:
use strict;
use warnings;
use List::Compare;
open my $file1, '<file1.txt' or die $!;
my @file1 = <$file1>;
close $file1;
open my $file2, '<file2.txt' or die $!;
my @file2 = <$file2>;
close $file2;
my $lc = List::Compare->new(\@file1, \@file2);
my @file1Only = $lc->get_Lonly; # L(eft array)only
for(@file1Only) { print }
my @bothFiles = $lc->get_intersection;
for(@bothFiles) { chomp; print "$_\t$_\n" }
my @file2Only = $lc->get_Ronly; # R(ight array)only
for(@file2Only) { print "\t\t$_" }
contestado el 04 de mayo de 12 a las 18:05
No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas perl or haz tu propia pregunta.
Echa un vistazo a stackoverflow.com/questions/4960275/… - Jason Clark
¿realmente necesita repetir la etiqueta de la fila cada vez? construir un hash de arrayrefs sería bastante fácil. - Joel Berger