• Publicidad

Búsqueda binaria en un fichero

¿Ya sabes lo que es una referencia? Has progresado, el nível básico es cosa del pasado y ahora estás listo para el siguiente nivel.

Búsqueda binaria en un fichero

Notapor rfm » 2007-11-20 17:09 @756

Hola todos.

En mi actual proyecto accedo secuencialmente a un fichero de log en busca de una fecha en concreto y me preguntaba si no es más eficiente una búsqueda por algún método como quicksort, es decir ir a la mitad del fichero, comparar, si es mayor, ir a la mitad de la mitad anterior, etc...

¿Hay alguna función ya implementada en Perl o hay que implementar el código?

Muchas gracias y un saludo
rfm
Perlero nuevo
Perlero nuevo
 
Mensajes: 47
Registrado: 2007-11-09 09:00 @417

Publicidad

Notapor explorer » 2007-11-20 18:45 @823

Humm... File::SortedSeek. Y seguro que debe haber alguno más, si el fichero de log es de un formato conocido...

Y si el fichero de log cabe en memoria, sería fácil hacer una búsqueda binaria. Hay otro módulo con la búsqueda binaria ya implantada: Search::Binary.
Última edición por explorer el 2007-11-21 08:31 @397, editado 1 vez en total
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Quicksort de un fichero

Notapor Jenda » 2007-11-21 04:27 @227

rfm escribiste:En mi actual proyecto accedo secuencialmente a un fichero de log en busca de una fecha en concreto y me preguntaba si no es más eficiente una búsqueda por algún método como quicksort, es decir ir a la mitad del fichero, comparar, si es mayor, ir a la mitad de la mitad anterior, etc...


No es quicksort, es la búsqueda binaria. Podrías hacerlo, pero no creo que te vaya a ayudar mucho. Ora vas a tener que buscar los fines y principios de las líneas cada vez, ora preparar un array con los posiciones de líneas en el fichero. Lo primero va a complicar el código mucho, lo segundo sólo ayuda si buscas más fechas.

Si buscas más fechas puedes recordar las líneas o las posiciones y hacer algo así:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl
use strict;
use warnings;

use constant FECHA => 3; # en que posición de cada línea es la fecha

sub prepara_datos {
  my ($fichero) = @_;
  my %fechas;
  open my $IN, '<', $fichero or die "No se puede abrir '$fichero': $^E\n";
  my $posicion=0;
  while (<$IN>) {
    chomp;
    my @columns = split /\t/, $_;
    $fechas{$columns[FECHA]} = $posicion;
    $posicion = tell($IN);
  }
  return ( $IN, \%fechas);
}

sub busca_fecha {
  my ($FICHERO, $fechas, $fecha) = @_;
  if (exists $fechas->{$fecha}) {
    seek($FICHERO, $fechas->{$fecha}, 0);
    my $linea = <$FICHERO>;
    chomp($linea);
    my @columns = split /\t/, $linea;
    return \@columns;
  } else {
    return; # la fecha no esta en el fichero
  }
}

#...
my ($FICHERO, $fechas) = prepara_datos( $fichero);

foreach my $fecha (@fechas_para_buscar) {
  my $datos = busca_fecha( $FICHERO, $fechas, $fecha);
  if (! $datos) {
   print "No he encontrado $fecha!\n";
  } else {
     # haga algo con @$datos
  }
}
 
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4


Si el fichero es demasiado grande y no puedes guardar todas las fechas y posiciones en un array, puedes usar BerkeleyDB.pm o AnyDBM_File.pm módulo para poner los datos al disk.

Y si quieres buscar usando otros datos o encontrar todos los datos entre dos fechas o algo similar, puedes importar todos los datos en una base de datos (por ejemplo con DBD::SQLite - es una base de datos en un módulo, no necesitas instalar nada más).

Jenda
Jenda
Perlero nuevo
Perlero nuevo
 
Mensajes: 132
Registrado: 2007-10-29 06:31 @313
Ubicación: Praga, Republica Checa

Notapor rfm » 2007-11-21 06:29 @312

Lo que quiero hacer realmente es posicionarme en la primera línea que contenga una fecha en concreto y a raíz de ahí parsear el resto del fichero de log (esto último lo tengo ya implementado).

Entonces la cuestión es que no me tarde tanto en comprobar línea a línea si coincide o no con la fecha que le paso.

¿Alguna otra sugerencia?

Miraré lo del sqlite.

Muchas gracias a los dos.
rfm
Perlero nuevo
Perlero nuevo
 
Mensajes: 47
Registrado: 2007-11-09 09:00 @417

Notapor explorer » 2007-11-21 08:18 @387

Se podría hacer una búsqueda binaria moviendo el puntero de lectura del fichero, y luego hacer una lectura de una línea completa para ver la fecha que tiene esa línea, y seguir buscando, hasta encontrarlo.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor explorer » 2007-11-21 08:44 @405

Acabo de darme cuenta de que lo que he dicho en el último mensaje, lo hace el módulo que te comenté antes: File::SortedSeek.

He mirado el código fuente y hace exactamente eso.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14486
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Notapor Norther » 2007-11-22 13:51 @619

También es casualidad que ayer en clase hicimos búsqueda binaria y dicotómica en C :P
Norther
Perlero nuevo
Perlero nuevo
 
Mensajes: 117
Registrado: 2007-07-24 13:47 @616
Ubicación: Asturias


Volver a Intermedio

¿Quién está conectado?

Usuarios navegando por este Foro: Bing [Bot] y 4 invitados

cron