Newsgroup: it.comp.lang.perl
Titolo: creare un hash ordinato

Supponiamo d'avere un semplice hash che ha come chiavi dei valori
alfanumerici, e come valori dei numeri.
Sono riuscito senza problemi ad ordinarlo nella maniera riportata su
libri/siti:
my @occ = sort {($a cmp $b) or ($unsorted{$b} <=> $unsorted{$a})} keys
%unsorted;
foreach (@occ)
{
        print "$_ --> $unsorted{$_}\n";
}
In questo modo riesco a stampare il mio hash ordinato.
Quello che però vorrei ottenere è un nuovo hash (chiamiamolo %sorted) che
contenga gli stessi valore di %unsorted ma nell'ordine corretto.
Ho fatto alcuni tentativi (sia pratici che di ricerca in internet) ma non
sono riuscito a risolvere il problema...
Nessuno ha idee in merito?
Grazie in anticipo
        micron

 
Con gli hash ordinari non č possibile. Tuttavia, se tu avessi cercato nelle 
FAQ...
       How can I always keep my hash sorted?
       You can look into using the DB_File module and tie() using
       the $DB_BTREE hash bindings as documented in "In Memory
       Databases" in DB_File.  The Tie::IxHash module from CPAN
       might also be instructive.
Max

 nelle FAQ...
L'avevo visto, ma pensavo/speravo che ci fosse un modo per aggirare il
problema... :)
grazie
        micron

Allora... ho provato ad usare Tie::IxHash e devo dire che funziona
perfettamente.
Si è presentato però un nuovo problema, direi molto singolare...
Ho creato una funzione che restituisce un hash ordinato usando Tie::IxHash.
Purtroppo all'interno della funzione il nuovo hash sorted è ordinato, però
quando viene restituito e quindi copiato in un hash sorted_main accade un
cosa strana: quest'ultimo hash (sorted_main) torna "disordinato".
Ma vi pare normale una cosa del genere?
Cosa mi consigliate di fare?
Vi allego un esempio pratico del mio problema:
~~~~~~ BEGIN CUT HERE ~~~~~~~~~~~~~~~~~~~~
#!/usr/bin/perl
use Tie::IxHash;
sub sort_dec_key
{
        my %unsorted = %{$_[0]};
 
        my @freq = sort {($a cmp $b) or ($unsorted{$b} <=> $unsorted{$a})} keys
%unsorted;
        my %sorted;
        tie(%sorted, Tie::IxHash,);
 
        foreach (@freq)
        {
                $sorted{$_} = $unsorted{$_};
        }
        print "Sorted keys\n";
        foreach (keys %sorted)
        {
                print "$_ --> $sorted{$_}\n";
        }
 
return %sorted;
}
%myhash = ("Z"=>"ultimo", "A" => "primo", "C" => "in mezzo");
print "Originale:\n";
foreach (keys %myhash)
{
        print "$_ --> $myhash{$_}\n";
}
%myhash2 = sort_dec_key (\%myhash);
print "\nDovrebbe essere ordinato, pero'...\n";
foreach (keys %myhash2)
{
        print "$_ --> $myhash2{$_}\n";
}
~~~~~~ END CUT HERE ~~~~~~~~~~~~~~~~~~~~
Tra le altre cose ho visto che Tie::IxHash _non_ permette di usare
contemporaneamente la direttiva "use strict", non vi sembra una cosa grave?
Grazie in anticipo
        micron

 "disordinato".
Ma non c'è niente di strano. L'abbiamo già detto: con gli hash ordinari non
c'è modo di imporre un determinato ordine delle chiavi. '%myhash2' è un
hash ordinario, che accidentalmente contiene una copia del contenuto di
'%sorted'. 
Max

 Cosa mi consigliate di fare?
Puoi restituire %sorted per riferimento
    return \%sorted 
e usarlo in questo modo anche al di fuori della funzione.
  $sorted_ref = sort_dec_key (\%myhash);
 
  for my $k( keys %{ $sorted_ref } )
  {
         print $k, "-->", $sorted_ref->{$k}, "\n";
  }
MM

 Purtroppo all'interno della funzione il nuovo hash sorted č ordinato, perņ

Puoi usare "strict" con Tie::IxHash. L'errore che ti da
dipende dal mancato uso delle virgolette.
Quanto al restituire un hash ordinato, dovresti lavorare un po sulle
references.
Ecco il tuo esempio con quelche correzione. Questo tiene l'hash ordinato.
vedi anche
http://perldoc.perl.org/search.html?q=perlref
# ----------------------------------------------------------
#!/usr/bin/perl
use strict;
use warnings;
use Tie::IxHash;
sub sort_dec_key
{
     my $unsorted = shift;
     my %sorted;
     tie(%sorted, 'Tie::IxHash'); # <--- virgolette!
     $sorted{$_} = $unsorted->{$_}
             for  sort {($a cmp $b) or ($unsorted->{$b} <=> $unsorted->{$a})}
                 keys %$unsorted;
     print "Sorted keys\n";
     print "$_ --> $sorted{$_}\n" for keys %sorted;
     return \%sorted;  # hash reference!
}
my %myhash = ("Z"=>"ultimo", "A" => "primo", "C" => "in mezzo");
print "Originale:\n";
print "$_ --> $myhash{$_}\n" for keys %myhash;
my $myhash2 = sort_dec_key (\%myhash);  # hash reference!
print "\nDovrebbe essere ordinato, pero'... (č ordinato!)\n";
print "$_ --> $myhash2->{$_}\n" for keys  %{ $myhash2 };
# ----------------------------------------------------------
ciao
gmax
-- 
   ____ ____  _____ _   _
  / _  |    \(____ ( \ / )
( (_| | | | / ___ |) X (
  \___ |_|_|_\_____(_/ \_)
(_____|
MySQL Certified Professional
Sapere, saper fare, fare, far sapere
http://gmax.oltrelinux.com

Cosa mi consigliate di fare?
Rinuncia ad ordinare gli hash.
O usa un'altra struttura dati, se ti è necessario. Il suggerimento riguardo
l'uso di Tie::IxHash credo che vada in questo senso: immagino che si
proponga di usarlo INVECE, piuttosto che PER.
Ciao.

 
http://perldoc.perl.org/search.html?q=perlref
Devo tornare a rileggerlo, sono alle prime armi con perl e devo dire che si
resta sempre spiazzati dalle sue innumerevoli sintassi...
Grazie ancora
        micron

ti serve una lista ordinata usi un array.
Già, però vale la pena di sottolineare che un array ordinato con accesso
anche per chiave non è, di per sè, una struttura dati impossibile da
realizzare o che assolutamente non possa avere una sua qualche utilità: le
"Collection" di Visual Basic sono così, e sono, per certi versi, comode.
Il punto è: in Perl questa struttura non esiste, o non esiste come
struttura dati nativa. Come corollario, esistono sufficienti strumenti da
renderla non necessaria.
Ciò non toglie, la richiesta ha una sua legittimità; è il tentativo di
soddisfarla pervertendo la natura degli hash che è destinato a scontrarsi
con innumerevoli e, credo, insormontabili difficoltà.
Ciao.