Primero: los programadores de Perl no escribimos scripts. Hacemos programas
Segundo... el programa en sí
- En vez de un declare() y un execute(), usaría un selectall_arrayref() (no probado):Using perl Syntax Highlightingmy @array = @{ $dbh->selectall_arrayref("select calle FROM dir where completo = '' GROUP BY direc ORDER BY direc") };Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
Lo mismo para @array2. El objetivo es tenerlo todo en arrays, que facilitan la nomenclatura posterior, aparte de que Perl se ahorra varios cálculos a la hora de hacer desreferencias, como cuando queremos averiguar el número de elementos del array. - Todos los if() hacen lo mismo, así que se pueden simplificar en uno solo.
Quedaría algo así (no probado):
Using perl Syntax Highlighting
my @array1 = @{ $dbh->selectall_arrayref("select calle FROM dir where completo = '' GROUP BY direc ORDER BY direc") };
my @array2 = @{ $dbh->selectall_arrayref("select UCASE(calle), compl FROM c1 GROUP BY calle ORDER BY calle") };
$dbh->disconnect();
for my $linea1 ( @array1 ) { ### Normalizando [||| ] % Completado \n
for my $linea2 ( @array2 ) {
my $smlty = String::Trigram::compare( $linea1->[0], $linea2->[0], minSim => 0.5, ngram => 7, );
if ( $smlty >= 0.5 ) {
printf "[%s]\t=>\t[%s][%s] %.2f\n", $linea1->[0], $linea2->[0], $linea2->[1], 100*$smlty;
}
}}
my @array2 = @{ $dbh->selectall_arrayref("select UCASE(calle), compl FROM c1 GROUP BY calle ORDER BY calle") };
$dbh->disconnect();
for my $linea1 ( @array1 ) { ### Normalizando [||| ] % Completado \n
for my $linea2 ( @array2 ) {
my $smlty = String::Trigram::compare( $linea1->[0], $linea2->[0], minSim => 0.5, ngram => 7, );
if ( $smlty >= 0.5 ) {
printf "[%s]\t=>\t[%s][%s] %.2f\n", $linea1->[0], $linea2->[0], $linea2->[1], 100*$smlty;
}
}}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Ahora quedaría la parte de decidir qué hacer cuando los casos de coincidencia. Primero habría que decidir cuándo hay una coincidencia plena. Si suponemos que es cuando la similitud es superior al 90%, entonces podemos incluir una línea al final del bucle más interior con esto:
Using perl Syntax Highlighting
Así, saltamos a probar la siguiente calle del bucle más exterior.
Lo interesante es el poder sacar elementos de los array a medida de que vamos encontrando coincidencias.
Pero... no es tan sencillo. O bueno... es sencillo pero nada recomendable.
Quiero decir que se podría poner una instrucción splice() en el bucle más interior para extraer el elemento que nos interesa (habría que cambiar la forma de recorrer los arrays, pasando de elementos a índices de elementos), y Perl reduciría el tamaño del array.
El problema es que, en la documentación, aconsejan no hacer nada de esto. Podría ser una operación no bien soportada en futuras versiones de Perl.
Hay varias soluciones: una de ellas sería guardar los índices de las calles encontradas en los arrays. Y luego, indefinir esa posición en el segundo array, para que el bucle más interno vaya más rápido.
Algo así (no probado):
Using perl Syntax Highlighting
my @array1 = @{ $dbh->selectall_arrayref("select calle FROM dir where completo = '' GROUP BY direc ORDER BY direc") };
my @array2 = @{ $dbh->selectall_arrayref("select UCASE(calle), compl FROM c1 GROUP BY calle ORDER BY calle") };
$dbh->disconnect();
my @calles_encontradas;
for my $i ( 0 .. $#array1 ) { ### Normalizando [||| ] % Completado \n
for my $j ( 0 .. $#array2 ) {
next if !$array2[$j]; # Saltamos si ya fue encontrada
my $smlty = String::Trigram::compare( $array1[$i][0], $array2[$j][0], minSim => 0.5, ngram => 7, );
if ( $smlty >= 0.5 ) {
printf "[%s]\t=>\t[%s][%s] %.2f\n", $array1[$i][0], $array2[$j][0], $array2[$j][1], 100*$smlty;
if ( $smlty >= 0.9 ) {
push @calles_encontradas, [$i, $j];
$array2[$j] = undef;
}
}
}}
my @array2 = @{ $dbh->selectall_arrayref("select UCASE(calle), compl FROM c1 GROUP BY calle ORDER BY calle") };
$dbh->disconnect();
my @calles_encontradas;
for my $i ( 0 .. $#array1 ) { ### Normalizando [||| ] % Completado \n
for my $j ( 0 .. $#array2 ) {
next if !$array2[$j]; # Saltamos si ya fue encontrada
my $smlty = String::Trigram::compare( $array1[$i][0], $array2[$j][0], minSim => 0.5, ngram => 7, );
if ( $smlty >= 0.5 ) {
printf "[%s]\t=>\t[%s][%s] %.2f\n", $array1[$i][0], $array2[$j][0], $array2[$j][1], 100*$smlty;
if ( $smlty >= 0.9 ) {
push @calles_encontradas, [$i, $j];
$array2[$j] = undef;
}
}
}}
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4
Al final tenemos un array, @calles encontradas, que contiene los índices dentro de los arrays, de las calles que más coinciden.
Naturalmente, estamos destruyendo la información del segundo array, así que si queremos saber qué valores eran, tendremos que hacer otra consulta a la base de datos. O crear, antes del bucle, una copia de ese array en uno nuevo. Para esto último, no vale con hacer un '='. Como estos arrays son estructuras complejas (array de array), deberás usar un módulo, como por ejemplo Clone, para hacer esa copia. O crear un array que contenga referencias a los elementos del segundo array. En fin, hay varias soluciones. La idea es jugar con la información que tenemos, pero que nos permite ahorrar el máximo posible de tiempo haciendo el mínimo de comparaciones, asignaciones, y ciclos. Y lo dicho para el segundo array se puede extender al primero, si estamos seguros de que, si dos calles coinciden en ambos arrays, los podemos sacar porque no habrá otra calle del segundo array que coincide con alguna del primero.