• Publicidad

Crear un hash a partir de array usando map

¿Apenas comienzas con Perl? En este foro podrás encontrar y hacer preguntas básicas de Perl con respuestas aptas a tu nivel.

Crear un hash a partir de array usando map

Notapor pablgonz » 2016-07-04 07:59 @374

Hola a todos de nuevo, estoy tratando de crear un %hash con algunas frases que necesito cambiar.

Las palabras se encuentran dentro de un array y usando map, agrego un mismo texto a todas las palabras contenidas y luego armo el %hash. El código es el siguiente:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.22;
  3. use Data::Dumper;
  4.  
  5. ### @array con las palabras de entorno
  6. my @ext_env  = qw (
  7.     postscript tikzpicture pgfpicture ganttchart circuitikz
  8.     forest tikzcd dependency pspicture psgraph
  9.     );
  10.  
  11. ### añado \begin{
  12. my $begin_env = join "\n", map { qq/\\begin\{$_/ } @ext_env;
  13. my @begin_env  = split /\n/, $begin_env;
  14.  
  15. ### añado \BEGIN{
  16. my $Begin_env = join "\n", map { qq/\\BEGIN\{$_/ } @ext_env;
  17. my @Begin_env  = split /\n/, $Begin_env;
  18.  
  19. ### añado \end{
  20. my $end_env = join "\n", map { qq/\\end\{$_/ } @ext_env;
  21. my @end_env  = split /\n/, $end_env;
  22.  
  23. ### añado \END{
  24. my $End_env = join "\n", map { qq/\\END\{$_/ } @ext_env;
  25. my @End_env  = split /\n/, $End_env;
  26.  
  27. ### ahora creamos %hash con las palabras cambiadas
  28. my %begenv_in;
  29. @begenv_in{@begin_env} = @Begin_env;
  30. my %endenv_in;
  31. @endenv_in{@end_env} = @End_env;
  32.  
  33. ### juntamos todo en un solo %hash
  34. my %cambios_in = (%begenv_in, %endenv_in);
  35.  
  36. print Dumper(\%cambios_in);
  37.  
  38. __END__
  39.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4
logro armar el %hash, pero son muchas líneas (según yo) y repetiré el código con otro array. Sé que con map puedo armar directamente el %hash. ¿Puedo hacer el código más corto?

Saludos,
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Publicidad

Re: Crear un hash a partir de array usando map

Notapor explorer » 2016-07-04 15:31 @688

En vez de tanto map{}, yo he usado los bucles for() de toda la vida ;)
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.22;
  3.  
  4. my @ext_env  = qw (
  5.     postscript    tikzpicture pgfpicture ganttchart circuitikz
  6.     forest tikzcd dependency  pspicture  psgraph
  7. );
  8.  
  9. my %cambios_in;
  10.  
  11. for my $ext_env (@ext_env) {
  12.     for my $prefix (qw(begin end)) {
  13.         $cambios_in{"\\$prefix\{$ext_env"} = "\\\U$prefix\E\{$ext_env";
  14.     }
  15. }
  16.  
  17. use Data::Dumper;
  18. say Dumper \%cambios_in;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear un hash a partir de array usando map

Notapor pablgonz » 2016-07-04 20:45 @906

Genial, tu solución, como siempre, funciona perfecto, me has ahorrado un montón de my :D

Para variar, un par de consultas:
1. Cuando usas \U$prefix\E, funciona como uc, ¿estoy en lo correcto?
2. Como tengo varios @array sobre los cuales deseo efectuar la misma operación para crear un %hash, ¿Se podría escribir el código como una función? Algo como my %nombre_hash = crearhash(@array);.

Agradecido,
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: Crear un hash a partir de array usando map

Notapor explorer » 2016-07-07 16:34 @732

1. En efecto. Perl tiene unas pocas secuencias de escape que hacen ese trabajo. Están descritas en la sección Quote and Quote-like Operators de perlop.

2. Sí que se puede escribir una función, pero hay que tener cuidado de un detalle: cuando pasamos un array como argumento a una función, Perl 5 (pero no Perl 6) "aplana" el contenido del array. Eso quiere decir que, en realidad, estamos pasando como argumentos todos los elementos del array. Si el array tiene centenares o miles de elementos, puede enlentecerse mucho el programa. Y lo mismo a la salida: si queremos un hash, pues eso implica pares de claves/valores. Si son muchos, pues más lentitud.

Si son pequeños, pues puede valer hacerlo de esa manera. Si no, es mejor pasar referencias:

my $nombre_hash_ref = crearhash(\@array);

De esa manera, solo estamos pasando un único valor a la entrada (un escalar, que es una referencia al verdadero array). Y a la salida, devolvemos también un único valor (otro escalar, que es la referencia al hash que hemos creado dentro de la función.

Por ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.22;
  3. use feature 'signatures';                      # estas dos líneas permiten que las sub tengan parámetros
  4. no warnings "experimental::signatures";        # en la definición (firmas de subrutinas)
  5.  
  6.  
  7. my @ext_env  = qw (
  8.         postscript    tikzpicture pgfpicture ganttchart circuitikz
  9.         forest tikzcd dependency  pspicture  psgraph
  10. );
  11.  
  12. my $cambios_in_ref = crearhash(\@ext_env);     # pasamos el array como referencia
  13.  
  14. say $cambios_in_ref->{'\\begin{forest'};       # ejemplo de acceso al hash desde su ref.
  15.  
  16. my %cambios_in = %{crearhash(\@ext_env)};      # otro ejemplo: convertimos la ref. de hash en hash (más bien, copiamos uno en otro)
  17.  
  18. say $cambios_in{'\\begin{forest'};             # acceso al hash de forma normal
  19.  
  20.  
  21. sub crearhash ($array_ref) {                   # la referencia que recibimos
  22.     my %cambios;                               # aquí guardamos el resultado
  23.  
  24.     for my $item (@{$array_ref}) {             # recorremos el array
  25.         for my $prefix (qw(begin end)) {
  26.             $cambios{"\\$prefix\{$item"} = "\\\U$prefix\E\{$item";
  27.         }
  28.     }
  29.  
  30.     return \%cambios;                          # devolvemos una ref. al hash
  31. }
  32.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear un hash a partir de array usando map

Notapor pablgonz » 2016-07-08 14:09 @631

Gracias por la respuesta, la verdad es que los @array con los que voy a trabajar son muy pequeños, como máximo tendrán 50 elementos (en un caso extremo) y la verdad es que el hash creado solo lo usaré en una expresión regular, es decir, no accederé a las claves de este de manera individual.

Estuve buscando un poco de información sobre cómo pasar un @array a una función y devolver un %hash y me topé con las referencias y los prototipos para estos casos, eso sí, el pragma use feature 'signatures'; no lo había visto.

Lo dejé así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/env perl
  2. use v5.22;
  3. use Data::Dumper;
  4.  
  5. # array
  6. my @verb_write = qw (
  7.     filecontents tcboutputlisting tcbexternal extcolorbox
  8.     extikzpicture VerbatimOut verbatimwrite
  9.     );
  10.  
  11. my @ext_env  = qw (
  12.         postscript    tikzpicture pgfpicture ganttchart circuitikz
  13.         forest tikzcd dependency  pspicture  psgraph
  14. );
  15.  
  16. # hash
  17. my %cambios_in = crearhash(@verb_write);
  18.  
  19. my %combios_out = crearhash(@ext_env);
  20.  
  21. # subrutina
  22. sub crearhash{
  23.         my %cambios;
  24.  
  25.     for my $aentra(@_){
  26.                 for my $prefix (qw(begin end)) {
  27.                 $cambios{"\\$prefix\{$aentra"} = "\\\U$prefix\E\{$aentra";
  28.                         }
  29.                 }
  30.     return %cambios;
  31. }
  32.  
  33. # regex
  34. my %cambio = (%cambios_in);
  35. my $busco = join "|", map {quotemeta} sort { length($a)<=>length($b) } keys %cambio;
  36.    
  37. print  Dumper $busco;
  38.  
  39. __END__
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

¿Se puede escribir la función pasando referencias sin ocupar use feature 'signatures';?

Saludos,
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: Crear un hash a partir de array usando map

Notapor explorer » 2016-07-08 17:03 @752

Claro, accediendo al array especial @_, como siempre.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear un hash a partir de array usando map

Notapor pablgonz » 2016-07-08 19:58 @873

Entonces, ¿la variable especial @_ ya es una referencia al @array de entrada (o a una lista)?

Pensé que se debía declarar de forma explicita la referencia, evitando usar prototipos, algo como:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. # subrutina dos usando referencias
  2. sub crearhash_dos{
  3.     my %cambios;
  4.     my ($array_ref) = @_;
  5.     my @entrada = @{ $array_ref };
  6.     for my $aentra(@entrada){
  7.         for my $prefix (qw(begin end)) {
  8.             $cambios{"\\$prefix\{$aentra"} = "\\\U$prefix\E\{$aentra";
  9.         }
  10.     }
  11.     return %cambios;
  12. }
  13.  
  14. my %cambios_tmp = crearhash_dos(\@ext_env);
  15. print  Dumper \%cambios_tmp;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Si entendí bien, esta subrutina sería equivalente a la primera subrutina que escribí en la cual pasaba el array de entrada a la variable especial @_.

Agradecido por las respuestas y la explicaciones :D
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)

Re: Crear un hash a partir de array usando map

Notapor explorer » 2016-07-09 06:12 @300

La variable @_ almacena los argumentos que se pasan a la subrutina.

Si es una referencia, pues es un solo argumento, un solo elemento dentro de @_.
Si es un array (desplegado), pues entonces hay tantos elementos dentro de @_ como elementos hay en el array:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. crearhash(@array);
  2.  
  3. sub crearhash {
  4.     my @array = @_;
  5.     for my $aentra (@array) {
  6.        ...;
  7. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


o incluso, más rápido y directo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. crearhash(@array);
  2.  
  3. sub crearhash {
  4.     for my $aentra (@_) {
  5.        ...;
  6. }
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14476
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: Crear un hash a partir de array usando map

Notapor pablgonz » 2016-07-13 11:48 @533

Muchas gracias por la explicación, ajustaré algunas líneas de otras cosas que he escrito usando esta información.

Saludos,
Pablo
pablgonz
Perlero nuevo
Perlero nuevo
 
Mensajes: 236
Registrado: 2010-09-08 21:03 @919
Ubicación: Concepción (Chile)


Volver a Básico

¿Quién está conectado?

Usuarios navegando por este Foro: No hay usuarios registrados visitando el Foro y 8 invitados