• Publicidad

Hash de Hash

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

Hash de Hash

Notapor felmoltor » 2007-05-25 14:39 @652

¡Hola!

Tengo un hash (%index) que deseo que sea multidimensional; en la primera componente va un nombre propio y en la segunda componente un número que indica la página en la que aparece ese nombre propio, y se le asigna el numero de veces que aparece ese nombre en la página.
No sé si como lo tengo hecho está bien y otro problema es que a la hora de recuperar la información de ese hash no sé hacerlo bien.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
...
...
   #aqui meto la información
   $index{$nomb}{$n_pagina}=$n_apariciones;
...
...
   #aquí más abajo quiero recuperar ordenado por el número de apariciones
   #en las páginas en las que aparece un nombre concreto
   my %paginas = %index{$buscar};
   foreach (sort values %paginas){  #ordenadas
      print "--> página número $_ \n";
   }
...
...
Coloreado en 0.002 segundos, usando GeSHi 1.0.8.4


Me falla en my %paginas = %index{$buscar}; y no sé si es por la forma de recuperar la información o porque he creado mal el hash.

¡Gracias!
felmoltor
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2007-03-08 17:04 @753

Publicidad

Notapor felmoltor » 2007-05-25 15:09 @673

¡Por cierto, me gustaría que las paginas salieran por orden de mayor apariciones a menor apariciones del nombre!
:D
felmoltor
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2007-03-08 17:04 @753

Notapor explorer » 2007-05-25 16:52 @744

Creo que se puede hacer así:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
#!/usr/bin/perl -l

use strict;

my %index = (
    pepe => {
                1 => 3,
                2 => 2,
               12 => 4,
            },
    juan => {
                4 => 5,
                5 => 6,
                6 => 3,
            },
    antonio => {
                9 => 10,
               },

);

foreach my $busca ( keys %index ) {

    print "$busca:";

    my %paginas = %{$index{$busca}};

    my %veces;
    %veces = map { $paginas{$_} => $_  } keys %paginas;
    # @veces{values %paginas} = keys %paginas;           # lo mismo que la línea anterior

    foreach my $vez ( sort { $b <=> $a } keys %veces ) {

        print "\t$vez veces en página $veces{$vez}";

    }
}

__OUTPUT__
pepe:
        4 veces en página 12
        3 veces en página 1
        2 veces en página 2
juan:
        6 veces en página 5
        5 veces en página 4
        3 veces en página 6
antonio:
        10 veces en página 9
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
El problema es que la estructura de datos guarda, y además correctamente, la información del número de apariciones, pero nos piden ordenar por justamente esos valores, no por las claves.

Si extraemos los valores con values, perdemos la relación entre cada valor con su clave correspondiente. Un valor, por sí solo, nos no indica a qué página pertenece.

En la solución propuesta, se plantea crear un hash %veces que es el mismo que %paginas, pero 'con el calcetín vuelto del revés', en que mapeamos cada número de apariciones a la página en que aparecen (se muestran dos formas de hacerlo).

Ahora ya podemos ordenar por las claves de ese hash, y esas claves nos llevarán a las páginas. Usamos sort con el comparador numérico (<=>) y además, para que nos salga de mayor a menor, tenemos que invertir el orden de la comparación, por lo que el $a y $b están cambiados de sitio.

Seguro que hay otras formas...
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 felmoltor » 2007-05-28 11:33 @523

Muchas gracias, no he probado exactamente el código que tu me das, pero he seguido esta solución de forma parecida y me he encontrado con un problema que creo que ocurre con este código que tu me has escrito también.
El problema es que en tu ejemplo has probado con apariciones del nombre diferentes, 4, 3, 2, etc... Pero en el momento en que se repitan valores de apariciones del nombre como 1, 2, 2, 1, etc. veces para un mismo nombre en diferentes páginas se sobrescribirán cuando le des la vuelta al calcetín como tu dices.
Prueba a poner en tu programa en vez de los valores que has puesto inicialmente estos:

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my %index = (
    pepe => {
                1 => 3,
                2 => 3,
               12 => 4,
            },
    juan => {
                4 => 5,
                5 => 5,
                6 => 3,
            },
    antonio => {
                9 => 10,
               },

);
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


y verás que no sale el número deseado de páginas que contienen ese nombre.
Gracias de todas formas por este código.
felmoltor
Perlero nuevo
Perlero nuevo
 
Mensajes: 8
Registrado: 2007-03-08 17:04 @753

Notapor explorer » 2007-05-28 15:40 @694

Efectivamente, el programa no resuelve el problema porque las nuevas claves no son únicas.

Bueno, pues otra solución es hacer una semi-transformada de Schwartz.

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

my %index = (
    pepe => {
                1 => 3,
                2 => 3,
               12 => 4,
            },
    juan => {
                4 => 5,
                5 => 5,
                6 => 3,
            },
    antonio => {
                9 => 10,
               },

);

foreach my $busca ( keys %index ) {

    print "$busca:";

    my %paginas = %{$index{$busca}};

    my @veces =
        sort { $a->[0] <=> $b->[0] }
        map  { [ $paginas{$_}, $_ ] }
        keys %paginas;

    foreach my $vez ( @veces ) {

        print "\t$vez->[0] veces en página $vez->[1]";

    }
}

__OUTPUT__
pepe:
        3 veces en página 1
        3 veces en página 2
        4 veces en página 12
juan:
        3 veces en página 6
        5 veces en página 4
        5 veces en página 5
antonio:
        10 veces en página 9
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4
El cambio que hacemos es el siguiente:
En %paginas tenemos una copia del número de páginas y veces que aparece cada término.
Con keys sacamos sus claves (que son los números de página).
Con map transformamos el número de veces que aparece el término de búsqueda y el número de página en un array anónimo de dos valores (observar los corchetes que forman el array anónimo).
El operador sort realiza la ordenación numérica (<=>) de los elementos que se le pasan. Esos elementos son arrays anónimos. Un elemento será $a y otro $b. Como tenemos que ordenar por número de veces que aparecen, hacemos la comparación por el primer componente del array anónimo. Por eso se pone $a->[0] y $b->[0].
El resultado es una lista de elementos en que cada elemento es un array anónimo, y ordenados por la primera componente. Se almacena directamente en @veces.
Sólo queda por pintar el array @veces, extrayendo los componentes de cada elemento.

Quedaría por resolver el problema de ordenar la salida también por número de páginas, pero eso es fácil, pues es sólo cuestión de añadir una comparación más al sort.
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


Volver a Básico

¿Quién está conectado?

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

cron