[Perl] Pregunta #3

Salvador Ortiz Garcia sog@msg.com.mx
14 Mar 2002 17:24:22 -0600


On Wed, 2002-03-13 at 01:54, Luis Guillot wrote:
>=20
> Lo que quiero hacer es algo parecido a lo tuyo, pero no es exacto. Yo ten=
go
> 2 ficheros planos, FICHERO1 y FICHERO2, con datos distintos, pero que tie=
nen
> en com=FAn un campo. Entonces yo quiero comparar este campo com=FAn en lo=
s dos
> ficheros, y los que sean iguales sacarlos.
>=20
> Es decir, por cada campo del FICHERO1, mirar en todo el FICHERO2, y la l=
=EDnea
> que coincida sacar unos datos.
> Esto me implica que por cada entrada del FICHERO1, tengo que recorrer tod=
o
> el FICHERO2. Y no son peque=F1os los ficheros. De ah=ED el alto coste tem=
poral.
>=20
> No me sirve la forma esta de unirlos. Por eso solo se me ha ocurrido lo d=
e
> JavaScript. =BFSe os ocurre algo mejor?
>=20

A ver, y a reserva de que no me queda claro que quieres decir con
"sacarlos", va una soluci=F3n. Supongamos:

Dos archivos de longitud variable F1 y F2, con registros inmensos.=20
Campos separados por ':';
Campos comunes: 2o de F1 y =FAltimo de F2.
Por "sacarlos" quieres imprimir la linea de F2 en que est=E1 el "match".=20

open(F1,"F1") or die 'No puedo bla bla...';
my %hash;
while($_ =3D <F1>) {  # Construyo un hash sobre el campo de inter=E9s
   chomp;           # Play safe
   my $dato =3D (split ':')[1];  # 2o campo
   $hash{$dato} =3D 'foo';   # 'foo'? Explicaci=F3n m=E1s adelante
}
open(F2,"F2") or die '...';
while($_ =3D <F2>) { # Recorro buscando un "matches"
   chomp;
   my $dato =3D (split ':')[-1];  # =FAltimo campo
   print "$_\n" if $hash{$dato};  # Match!
}
close(F1);
close(F2);
# Voil=E0

Como ver=E1s, s=F3lo tengo que recorrer cada archivo un=E1 sola vez, y no
guardo casi nada en memoria.

Por qu=E9 'foo'? Supongamos que en ese "sacarlos" requieres tambi=E9n datos
de F1, entonces guardas en $hash el/los datos en cuesti=F3n en vez de
'foo'.=20

Pero ojo, si requirieras mucho, digamos en caso extremo, toda el
registro de F1, y usaras "$hash{$dato} =3D $_", terminar=EDas habiendote
comido a memoria, indirectamente, todo F1.

Pero dijimos que era inmenso, as=ED que mejor usamos un 'foo' rarito:

    $hash{$dato} =3D tell(F1)-length($_);

Guardamos en el hash la posici=F3n+1 de cada l=EDnea, de forma que cuando l=
a
necesitamos en el segundo while usamos:

    if($hash($dato)) { # Match!
       seek(F1,$hash($dato)-1,0); # Busco la l=EDnea
       my $deF1 =3D <FI>;           # La leo
       print "$_ | $deF1";        # La de F2 y la de F1!
    }=20

Dudas hasta aqu=ED?

Existen a=FAn algoritmos m=E1s eficientes, pero tienen otros requerimientos=
,
espero que =E9ste te ayude.

Saludos.

Salvador Ortiz.


     =20