Requisito previo: Recursividad en Perl
Recursivo significa pertenecer o usar una regla o procedimiento que se puede aplicar repetidamente . Es el proceso de definir una función o calcular un número mediante la aplicación repetida de un algoritmo. Subrutina recursiva es un tipo de subrutina que se llama a sí misma como parte de su ejecución o está en un ciclo potencial de llamadas a funciones. Perl nos brinda la flexibilidad de usar subrutinas de forma iterativa y recursiva.
Un ejemplo simple que muestra el uso de la subrutina recursiva en Perl sería calcular el factorial de un número.
Ejemplo :
Perl
#!/usr/bin/perl # Perl Program to calculate Factorial sub factorial { my $n = $_[0]; # checking if that value is 0 or 1 if ($n == 0 || $n == 1) { return 1; } # Recursively calling the function with the next value # which is one less than current one else { return $n * factorial($n - 1); } } # Driver Code $n = 7; # Function call and printing result after return print "Factorial of a number $n is ", factorial($n);
Factorial of a number 7 is 5040
Recorriendo un árbol de directorio
Atravesar un árbol de directorios significa iterar o imprimir cada archivo y subdirectorio dentro de un directorio raíz. El árbol de directorios es una representación de los subdirectorios y archivos dentro de los subdirectorios y otros archivos dentro del directorio en forma de árbol que indica la relación padre-hijo entre estos directorios y los archivos respectivos.
Tanto Unix como WindowsLos sistemas organizan los directorios de archivos en una estructura de árbol. Aunque en Perl, atravesar un árbol de directorios o recorrer un árbol de directorios se puede hacer tanto de forma iterativa como recursiva, a menudo usamos el último cuando la cantidad de archivos o subdirectorios dentro de nuestra carpeta raíz es muy grande. Esto se debe a la rapidez y la menor cantidad de líneas de código escritas en una función recursiva en comparación con una iterativa. El último se utiliza cuando el número correspondiente de archivos es menor.
Usaremos File::Find para recorrer el sistema de archivos de forma iterativa y recopilar los nombres de los archivos.
Sintaxis:
use Archivo::Buscar;
find(\&buscado, @directories_to_search);
sub buscado {…}
use File::Find;
buscarprofundidad(\&buscado, @directorios_para_buscar);
sub buscado {…}
use File::Find;
find({ buscado => \&procesar, seguir => 1 }, ‘.’);
Ejemplo :
Perl
#!/usr/bin/perl use strict; use warnings; use File::Find::Rule; use File::Basename qw(basename); my $loc = "C:\Users\GeeksForGeeks"; my $file = 'final.txt'; my $expected = <STDIN>; chomp $expected; open(my $fh, '<', $expected) or die "Could not open '$expected' $!\n"; open(my $out, '>', $file) or die "Could not open '$file' $!\n"; my @paths = File::Find::Rule->file->name('*.pdf')->in($loc); my @files = map { lc basename $_ } @paths; my %case = map { $_ => 1 } @files; print $out "This file has been copied from ($loc)$file:\n"; while (my $name = <$fh>) { chomp $name; if ($case{lc $name}) { print "$name found\n"; } else { print $out "$name\n"; } } close $out; close $fh;
Salida: el archivo de origen se copia en el archivo de destino
En la próxima sección, discutiremos el recorrido recursivo del directorio raíz.
Atravesar recursivamente un árbol de directorios
El problema con la solución iterativa de recorrido, además de su baja velocidad y más líneas de código, es el hecho de que todos los subdirectorios dentro del directorio raíz deben tener la misma orientación y la misma cantidad de archivos dentro de ellos. De lo contrario, el recorrido puede convertirse en una tarea compleja. La solución recursiva juega un mejor papel en la solución del problema con la solución iterativa.
Ejemplo (recursivo):
Perl
#!/usr/bin/perl # Perl recursive Program to walk # through a directory tree use strict; use warnings; use 5.010; my $loc = shift || '.'; # Calling walk subroutine with # the location of the root directory walk($loc); # Subroutine definition sub walk { my ($case) = @_; # If case is not a directory itself return if not -d $case; # If case is a directory opendir my $dh, $case or die; while (my $sub = readdir $dh) { next if $sub eq '.' or $sub eq '..'; say "$case/$sub"; walk("$case/$sub"); } close $dh; return; }
Producción :
El código anterior le permitirá recorrer cada archivo en el directorio raíz y todos los subdirectorios presentes en el directorio raíz junto con los archivos y directorios dentro de estos subdirectorios.
Enfoque de arriba hacia abajo
El enfoque de arriba hacia abajo básicamente divide un problema o algoritmo complejo en múltiples partes más pequeñas (módulos) . Estos módulos se dividen aún más hasta que el módulo resultante es un programa que no se puede descomponer más.
Aquí, primero inicializamos una variable llamada $case que mantiene el archivo o el directorio que se está iterando o repitiendo. Entonces, si es un archivo , entonces la función simplemente imprime su nombre y pasa al siguiente archivo o directorio o si el caso $es un directorio, luego vuelve a llamar a la subrutina con la ubicación del directorio como la ubicación del directorio actual y luego recorre todos los archivos y subdirectorios dentro de ese directorio. Después de completar la función interna, el puntero regresa a la ubicación del directorio externo e imprime su nombre y luego se mueve al siguiente archivo o al directorio presente en el directorio raíz. Este es en realidad un enfoque de arriba hacia abajo típico que se usa en Perl para atravesar o caminar sobre un árbol de directorios.
Ejemplo :
Perl
use strict; use warnings; use 5.010; my $loc = shift || '.'; walk($loc); sub walk { my ($case) = @_; say $case; return if not -d $case; opendir my $dh, $case or die; while (my $sub = readdir $dh) { next if $sub eq '.' or $sub eq '..'; walk("$case/$sub"); } close $dh; return; }
Producción :
El código explicado en la sección Atravesar recursivamente un árbol de directorios es un ejemplo del enfoque de arriba hacia abajo que se usa en Perl.
Nota: la imagen de salida anterior muestra una pequeña parte de la salida completa, ya que hay muchos archivos y subdirectorios dentro del directorio raíz. Este código funciona bien para carpetas y directorios con una pequeña cantidad de subdirectorios.
Función recursiva
Una función recursiva tiene la siguiente forma general:
Función (argumentos) {
si es un caso simple, devuelve el valor simple // caso base / condición de parada;
de lo contrario, llame a la función con una versión más simple del problema
}
Ejemplo :
Perl
#!/usr/bin/perl # Perl Program to calculate Factorial sub myfunc { my $n = $_[0]; # checking if that value is # greater than 0 or not if ($n <= 0) { print "Now, You are on GFG portal.\n"; } # Recursively calling function with # the next value which is one less # than current one else { print "$n\n"; myfunc($n - 1); } } # Driver Code # Function call myfunc(3);
Producción:
Para que una función recursiva deje de llamarse a sí misma, necesitamos algún tipo de condición de parada. Si no es el caso base, entonces simplificamos nuestro cálculo usando la fórmula general. Una función recursiva tiene dos partes principales. El primero verifica alguna condición y regresa si se cumplió esa condición. Esto se denomina condición de detención o condición de parada . Luego, en algún punto posterior de la función, se llama a sí misma con un conjunto de parámetros diferente al que se llamó anteriormente.
¿Por qué se prefiere la recursión a la iteración?
- Viene con los aspectos positivos de escribir un código corto más limpio y simple.
- También es eficiente en términos de tiempo si se usa con memorización.
- Se desempeña mejor en la resolución de problemas basados en estructuras de árbol.
Publicación traducida automáticamente
Artículo escrito por BhavikBothra y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA