• Publicidad

hash con n niveles

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

hash con n niveles

Notapor anibalmauricio » 2009-09-23 11:02 @501

Hola, muy buenos días a todos.

Tengo la siguiente duda y no he podido dar con la solución y me gustaría contar con sus comentarios y ayuda. Tengo que hacer un hash, pero este hash debe ser de n niveles, es decir, puede contener n keys, ya que esto lo debo sacar de una tabla que es recursiva.

Me explico mejor: tengo una tabla que es recursiva, es decir se llama a sí misma. Lo que debo hacer es hacer un hash según las n veces que se llame a sí misma.

Hagamos de cuenta que es una tabla padre, pero en su misma tabla están sus hijos. Es una tabla de configuración y como no sé cuántos niveles puedan existir entonces debo crear este hash.

$hash{papa}{hijo}{nieto};

pero se puede dar el caso que el papá no tenga hijos o no tenga nietos.

$hash{papa};
$hash{papa}{hijo};


Cuando ya tenga este hash armado, ahora debo recorrerlo. Pero eso no es todo. Debo también asociar el campo que quiera registrar al papá, al hijo o al nieto que corresponda.

Supongamos que hay dos hijos, uno con id 2 y otro con id 1. El hijo con id 2 tiene a su vez dos hijos más, y el hijo con id 1 solo tuvo 1 hijo (o sea un nieto para el papá). No sé si me hago entender.

La verdad, no encuentro solución a este problema. he intentado con cualquier ciclo, for(), while(), foreach(), pero no encuentro la lógica adecuada para hacerlo. Soy muy nuevo en Perl y sé que ustedes me pueden ayudar en esto.

Se los agradezco de antemano.

Cordial saludo
Última edición por explorer el 2009-09-23 11:07 @505, editado 1 vez en total
Razón: Tildes
anibalmauricio
Perlero nuevo
Perlero nuevo
 
Mensajes: 10
Registrado: 2009-09-23 10:46 @490

Publicidad

Re: hash con n niveles

Notapor explorer » 2009-09-23 11:11 @508

Bienvenido a los foros de Perl en Español, anibalmauricio.

Hay algunos detalles sueltos que no están claros.

Dices que hay que recorrer la tabla de forma recursiva, pero no nos dices cómo se para esa recursividad.

Y tampoco tengo claro lo que quieres decir con "asociar el campo".

¿Podrías poner un ejemplo completo? Uno cortito sería interesante.

Y más interesante será ver el código que estás probando.
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: hash con n niveles

Notapor anibalmauricio » 2009-09-23 11:36 @525

:lol: :lol: :lol:
Qué pena, la verdad se me pasó.

Bueno, lo de asociar al campo me refiero al dato que tenga este registro en la base de datos. Me explico mejor.

Tengo que consultar unas cuentas de unos clientes y obtener unos registros de esa tabla; estas cuentas tienen el campo pcelementobalanceid que me indica a qué pcelementobalance corresponde. Supongamos que la tabla cuentas tiene un pclementobalanceid 4; ahora debo armar la consulta a la tabla pcelementobalance con el id que me devuelve la tabla de cuentas.

Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
pcelementobalance
id=4
nivel=3
descripcion=xxxxx
pcelementobalanceid=3
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4


Supongamos que aquí consulto al id 4 de la tabla pcelementobalance, pero la tabla tiene un campo que se llama así mismo (pcelementobalanceid), en este caso es 3, así que ahora debo consultar el 3 y así sucesivamente hasta que pclementobalance sea igual a vacío, es decir, el último nivel. Pero, al encontrar este registro, entonces esto me indica que debe ir un nivel en el hash, por ejemplo:

$hash{1}{2}{3}{4} = $vardelatablacuentas

pero ahora sigo con la otra cuenta y ésta tiene un pcelementobalanceid = 3, entonces se hace el mismo proceso, así que quedaría más o menos así:

$hash{1}{2}{3} = $vardelatablacuentas

el 1 sería el último nivel, el 2 el que tiene como pcelementobalanceid = 1, el 3 el que tiene pcelementobalanceid = 2 y así sucesivamente. No sé si ahora sea vea un poco más claro...

La verdad, del código no llevo mucho, pues no se me ocurre cómo hacerlo:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
$sql="select * from cuentas";
foreach my $ksql (@$sql){
        next unless $ksql ;
        $pcebCta = $$ksql {'pcelementobalanceorusid'};
        if ($pcebCta ne ''){
                while ($pcebCta != ""){
                        $rpcElementoBalance="select * from pcelementobalance where id=$pcebCta";
                        $pcebCta = "$$rpcElementoBalance{'pcelementobalanceid'}";
                        //supongo que aqui es donde se debe alimentar el hash
                }
        }
}
Coloreado en 0.004 segundos, usando GeSHi 1.0.8.4


Probablemente no encuentres clara esta sentencia; solo cambié la sintaxis de las consultas a SQL estándar porque aquí en el trabajo utilizan un motor totalmente diferente y utilizan algo más XML. Las consultas SQL que puse ahí solo las reemplazo según la sintaxis que maneja el motor de la empresa, así que no te preocupes si las sentencias no las ves claras.

Te agradezco mucho tu ayuda y por sobretodo la disposición que tienes, muchas gracias.
Última edición por explorer el 2009-09-23 11:48 @533, editado 1 vez en total
Razón: Ortografía, bloques de código
anibalmauricio
Perlero nuevo
Perlero nuevo
 
Mensajes: 10
Registrado: 2009-09-23 10:46 @490

Re: hash con n niveles

Notapor wladif » 2009-09-23 12:09 @548

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. foreach my $padre (keys %h) {
  2.    foreach my $hijo (keys %{ $h{$padre} } ) {
  3.       # En este punto, las variables $padre, $hijo están definidas
  4.       foreach my $nieto (keys %{ $h{$padre}{$hijo} } ) {
  5.          # En este punto, las variables $padre, $hijo, $nieto están definidas
  6.       }
  7.    }
  8. }
  9.  
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Me imagino que algo así es lo que necesitas para recorrer tu hash.

Para alimentarlo, no hay mucha complejidad. Si tienes un padre con un hijo, solo pon

$h{$padre}{$hijo} = 1;

El 1 sólo define que tiene algo, podrías usar un 0, un puntero a un array, un string, una referencia a una función, lo que quieras;

$h{$padre}{$hijo}{$nieto} = 1;

define finalmente lo que necesitas.

Por ejemplo:

$h{'Juan'}{'Pedro'}{'Diego'} = 1;

indica que Diego es hijo de Pedro que es hijo de Juan.

El hash se 'arma' solo. Ahora, si necesitas ver el contenido de tu hash, pon esto al comienzo de tu programa:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
use Data::Dumper;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Luego, cuando hayas llenado tu hash, si deseas ver cómo queda armado, solo pon:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print Dumper %h;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Y listo, tendrás tu estructura de hash impresa por consola de una forma bastante clara.
wladif
Perlero nuevo
Perlero nuevo
 
Mensajes: 5
Registrado: 2009-07-22 12:05 @545

Re: hash con n niveles

Notapor explorer » 2009-09-23 12:49 @575

Hummm... mejor

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
print Dumper \%h;
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Incluso mejor es usar el módulo Data::Dumper::Names, aunque no viene instalado por defecto :(
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: hash con n niveles

Notapor anibalmauricio » 2009-09-23 14:19 @638

Hola Joaquín, muchísimas gracias por tu gran ayuda y colaboración. La verdad, no me queda muy claro.

Entiendo lo que me quieres decir de recorrer los hash pero como lo planteas siempre habrán 3 niveles, padre, hijo y nieto. Pero ¿y en el caso de que hayan más niveles? ¿o menos? En este caso el hash sería dinámico, ¿verdad? ¿o estoy perdido? Porque como yo lo veo no sé cuántos niveles vaya a tener en el hash, ¿cómo se haría para crearlo con n niveles según el número de consultas que se hagan hasta llegar al pcelementobalanceid sea vacío? ¿Sí me hago entender?

De antemano, te agradezco muchísimo la ayuda y la presteza que has tenido en esta solución. Perdona por ser tan intenso, gracias.
Última edición por explorer el 2009-09-23 14:50 @659, editado 1 vez en total
Razón: Tildes
anibalmauricio
Perlero nuevo
Perlero nuevo
 
Mensajes: 10
Registrado: 2009-09-23 10:46 @490

Re: hash con n niveles

Notapor explorer » 2009-09-23 14:52 @661

Quien te ha dado la pista para recorrer el hash ha sido wladif. Y también tiene razón en el tema de que no tienes que preocuparte en "preparar" un hash para recibir los datos: el hash le puedes crear a medida de que vas leyendo la información.

A ver si se me ocurre un ejemplo...
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: hash con n niveles

Notapor anibalmauricio » 2009-09-23 15:03 @668

¡Uy! ¡Qué pena con ustedes, wladif! ¡Muchísimas gracias por tu ayuda! Y a ti, Joaquín te agradecería, bueno, más de lo que ya me has ayudado, te agradecería tu colaboración con un ejemplo; la verdad estoy un poco perdido ahora.

Se los agradezco.
anibalmauricio
Perlero nuevo
Perlero nuevo
 
Mensajes: 10
Registrado: 2009-09-23 10:46 @490

Re: hash con n niveles

Notapor explorer » 2009-09-23 19:02 @834

Bueno, el asunto es bastante complejo, o es que me he liado y no he encontrado una buena solución.

El caso es que el problema no está completamente descrito porque no se indica si las claves se mezclan entre sí. Quiero decir si las claves de la tabla, el camino que seguimos entre ellas, se intersecta con más de una clave principal.

Es decir, que podamos querer tener esto:
$hash{1}{2}{3}{4} = $vardelatablacuentas;

y esto, a la vez:
$hash{1}{2}{3} = $vardelatablacuentas;

Un hash no puede tener dos valores asociados a la misma clave (en el ejemplo, 3).

El siguiente ejemplo está montado con alfileres, así que seguro que no te sirve para tu problema, pero al menos sirve para ver lo complicado del asunto.

Si tenemos este fichero de texto, haciendo el papel de base de datos:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
id      nivel   descripcion     pcelementobalanceid
1       2       aaaaa           0
2       2       zzzzz           1
3       2       yyyyy           2
4       3       xxxxx           3
5       2       wwwww           0
6       2       qqqqq           5
7       3       sssss           0
8       2       vvvvv           0
9       2       ggggg           8
10      3       hhhhh           9
11      2       ooooo           10
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

entonces, con este programa:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use diagnostics;
  5.  
  6. use Data::Dumper::Names;
  7.  
  8. ## Leemos toda la cuenta
  9. my %cuenta;
  10.  
  11. open my $fichero, '<kk.txt';
  12. <$fichero>;                     # Obviamos la cabecera
  13. while (<$fichero>) {
  14.     chomp;
  15.     my @campos = split " ";     # leemos cada línea de la tabla
  16.     $cuenta{$campos[0]} = [ @campos ];
  17. }
  18. close $fichero;
  19.  
  20. ## Creamos la estructura jerárquica del hash
  21. my %hash;
  22.  
  23. for my $clave (sort {$a <=> $b} keys %cuenta) {
  24.  
  25.     my %hasito = %{ recorre($clave, $cuenta{$clave}[-2]) };  # devuelve un valor o un hash
  26.  
  27.     @hash{keys %hasito} = values %hasito;
  28. }
  29. print Dumper \%hash;
  30.  
  31. sub recorre {
  32.     my ($id, $hash_ref) = @_;
  33.  
  34.     my $nueva_id = $cuenta{$id}[-1];
  35.  
  36.     if ($nueva_id) {                        # Hay un nivel más de profundidad
  37.  
  38.         return recorre($nueva_id, { $id => $hash_ref } );
  39.     }
  40.  
  41.     return { $id => $hash_ref };                       # Caso de devolver solo el valor final
  42. }
  43.  
  44. __END__
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

sale:
Sintáxis: [ Descargar ] [ Ocultar ]
Using text Syntax Highlighting
%hash = (
          '8' => {
                   '9' => {
                            '10' => {
                                      '11' => 'ooooo'
                                    }
                          }
                 },
          '1' => {
                   '2' => {
                            '3' => {
                                     '4' => 'xxxxx'
                                   }
                          }
                 },
          '7' => 'sssss',
          '5' => {
                   '6' => 'qqqqq'
                 }
        );
Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4

que sí es una estructura de hash de hash, pero dudo que sea esto lo que realmente quieres.

Unos detalles sobre el programa:
  • El programa lee toda la base de datos a memoria, para no tener que hacer consultas de forma continuada para averiguar los datos de las claves que vamos siguiendo
  • No indicas qué valor se ha de guardar en la estructura, así que he puesto la de descripción
  • La columna nivel no se usa para nada
  • Digo que esto está montado con alfileres, porque si las líneas de la base de datos las leo en otro orden (quitar el comando sort{}), sale algo como esto:
    Sintáxis: [ Descargar ] [ Ocultar ]
    Using text Syntax Highlighting
    %hash = (
              '8' => {
                       '9' => {
                                '10' => 'hhhhh'
                              }
                     },
              '1' => {
                       '2' => {
                                '3' => {
                                         '4' => 'xxxxx'
                                       }
                              }
                     },
              '7' => 'sssss',
              '5' => 'wwwww'
            );
    Coloreado en 0.000 segundos, usando GeSHi 1.0.8.4
    El '6' y el '11' no están, porque son eliminados al ser sustituidos por claves posteriores.

Esto requiere más investigación, pero sería interesante ver un resultado real (aunque sea con datos falsos).
JF^D Perl programming & Raku programming. Grupo en Telegram: https://t.me/Perl_ES
Avatar de Usuario
explorer
Administrador
Administrador
 
Mensajes: 14480
Registrado: 2005-07-24 18:12 @800
Ubicación: Valladolid, España

Re: hash con n niveles

Notapor anibalmauricio » 2009-09-23 22:17 @970

Hola Joaquín. La verdad, sin palabras, muchísimas, muchísimas gracias. Me has dado mucho en qué pensar. Y sí, como tú dices, faltaron muchos detalles más, pero con lo que me has dicho me has ayudado muchísimo. Te lo agradezco infinitamente.

En el ejemplo que puse lo que hice estuvo mal, pues como tú dices, no especifiqué si se sobreescribían los índices o no, y la verdad, creo que independientemente de lo que hagamos se sobreescriben estos últimos, ¿verdad?

Voy a seguir trabajando en esto. Y tenlo por seguro que tan pronto como lo tenga terminado lo publicaré, para que tu lo veas y para ayuda y conocimiento de los demás. Tú me ayudaste, así que es justo que los demás se beneficien de lo que compartes.

Cordial saludo.
anibalmauricio
Perlero nuevo
Perlero nuevo
 
Mensajes: 10
Registrado: 2009-09-23 10:46 @490

Siguiente

Volver a Básico

¿Quién está conectado?

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