Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

How to sort hash tables alpha-numeric

by juo (Curate)
on Oct 18, 2003 at 05:27 UTC ( [id://300236]=perlquestion: print w/replies, xml ) Need Help??

juo has asked for the wisdom of the Perl Monks concerning the following question:

$keys{'C10'}->{'C10-1'}=1; $keys{'C10'}->{'C10-2'}=1; $keys{'C10'}->{'C10-20'}=1; $keys{'C10'}->{'C10-3'}=1; $keys{'C200'}->{'C200-1'}=1; $keys{'C200'}->{'C200-20'}=1; $keys{'C200'}->{'C200-3'}=1; $keys{'C200'}->{'C200-21'}=1; $keys{'C30'}->{'C30-1'}=1; $keys{'C30'}->{'C30-2'}=1; $keys{'C30'}->{'C30-30'}=1; $keys{'C30'}->{'C30-4'}=1; # Result should be : 'C10' => HASH(0x1832a58) 'C10-1' => 1 'C10-2' => 1 'C10-3' => 1 'C10-20' => 1 'C30' => HASH(0x1832b30) 'C30-1' => 1 'C30-2' => 1 'C30-4' => 1 'C30-30' => 1 'C200' => HASH(0x1835318) 'C200-1' => 1 'C200-3' => 1 'C200-20' => 1 'C200-21' => 1

Replies are listed 'Best First'.
Re: How to sort hash tables alpha-numeric
by Aragorn (Curate) on Oct 18, 2003 at 17:48 UTC
    Here's a solution using the so-called Schwartzian transform for sorting the keys (the leading "C" is stripped off, and the the key list is sorted by the number before the dash, and then by the number after the dash:
    #!/usr/bin/perl use warnings; use strict; my %keys; $keys{'C10'}->{'C10-1'}=1; $keys{'C10'}->{'C10-2'}=1; $keys{'C10'}->{'C10-20'}=1; $keys{'C10'}->{'C10-3'}=1; $keys{'C200'}->{'C200-1'}=1; $keys{'C200'}->{'C200-20'}=1; $keys{'C200'}->{'C200-3'}=1; $keys{'C200'}->{'C200-21'}=1; $keys{'C30'}->{'C30-1'}=1; $keys{'C30'}->{'C30-2'}=1; $keys{'C30'}->{'C30-30'}=1; $keys{'C30'}->{'C30-4'}=1; sub sorted { return map { $_->[0] } sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] } map { [ $_, split("-", substr($_,1)) ] } @_; } foreach my $key (sorted(keys %keys)) { print "'$key' => ", $keys{$key}, "\n"; foreach my $subkey (sorted(keys %{$keys{$key}})) { print " '$subkey' => $keys{$key}->{$subkey}\n"; } }

    Arjen

      This works perfect although I don't understand yet 100% how the Schwartzian transform works. Their is one small problem that I have with the code is that it should look for all leading characters to be split because now it substr only one but it could be more. (CR30-1 for example) So I tried to modify the code but no success.
      sub sorted { return map { $_->[0] } sort { $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2] } map { [ $_, split("-", s/^[A-Z]+//) ] } @_; } foreach my $key (sorted(keys %keys)) { print "'$key' => ", $keys{$key}, "\n"; foreach my $subkey (sorted(keys %{$keys{$key}})) { print " '$subkey' => $keys{$key}->{$subkey}\n"; } }
        The Schwartzian Transform is explained here by the person after who this sorting technique is named.

        A modified version of the sorted routine which also takes the leading letters into account:

        sub sorted { return map { $_->[0] } sort { $a->[1] cmp $b->[1] || $a->[2] <=> $b->[2] || $a->[3] <=> $b->[3] } map { [ $_, (/([A-Z]+)(\d+)(?:-(\d+)){1,2}/) ] } @_; }
        The split function is replaced by a regex which returns a list of letters and the numbers.

        Arjen

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://300236]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (7)
As of 2024-04-23 09:12 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found