http://www.perlmonks.org?node_id=663367

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

I have a hash of array as follow:

%person = { firstname => ['name1', 'name2', 'name3'], lastname => ['lname1', 'lname2', 'lname3'], city => ['city1','city2','city3'] }


So that
person1 has firstname = name1, lastname =lname1 & city=city1
person2 has firstname =name2, lastname = lname2 & city =city2 and so on....

How can i sort this hash for firstname?

Replies are listed 'Best First'.
Re: How do i sort a hash or array?
by moritz (Cardinal) on Jan 21, 2008 at 13:11 UTC
    You have chosen a really bad representation for sorting.

    You could transform your data to an array of hashes instead:

    my @persons = { firstname => 'name1', lastname => 'lname1', city => 'city1', }, { firstname => 'name2', lastname => 'lname2', city => 'city2', }, ... );

    And then sort with sort { $a->{firstname} cmp $b->{firstname} } @persons.

Re: How do i sort a hash or array?
by gam3 (Curate) on Jan 21, 2008 at 13:51 UTC
    Your code should read:
    %person = ( firstname => ['name1', 'name2', 'name3'], lastname => ['lname1', 'lname2', 'lname3'], city => ['city1','city2','city3'] );
    or
    $person = { firstname => ['name1', 'name2', 'name3'], lastname => ['lname1', 'lname2', 'lname3'], city => ['city1','city2','city3'] };
    If you really need your data to look like this you can sort it like this.
    %person = ( firstname => ['name2', 'name1', 'name3'], lastname => ['lname2', 'lname1', 'lname3'], city => ['city2','city1','city3'] ); for (map {$_->[1] } sort {$a->[0] cmp $b->[0] } map { [$person{firstname}[$_], $_] } (0 .. scalar @{$person{firstname}} - 1)) { printf("%s %s %s\n", $person{firstname}[$_], $person{lastname}[$_], $person{city}[$_]); }
    -- gam3
    A picture is worth a thousand words, but takes 200K.
Re: How do i sort a hash or array?
by tuxz0r (Pilgrim) on Jan 21, 2008 at 14:32 UTC
    Moritz is on the right track. You really need to rethink your data structure. The problems with the current representation is the amount of work it takes to sort (as the second poster related in his code snippets), the array's might get out of sync, etc. Storing them as an Array of Hash's makes more sense and is easier to not only understand but code for.

    ---
    s;;:<).>|\;\;_>?\\^0<|=!]=,|{\$/.'>|<?.|/"&?=#!>%\$|#/\$%{};;y;,'} -/:-@[-`{-};,'}`-{/" -;;s;;$_;see;
    Warning: Any code posted by tuxz0r is untested, unless otherwise stated, and is used at your own risk.

Re: How do i sort a hash or array?
by ikegami (Patriarch) on Jan 21, 2008 at 17:52 UTC

    A AoH would be better than a HoA. You want to work with a list of people.

    However, it's still possible to do what you want with the structure you have. What you need to do is sort the indexes.

    my @sorted = sort { $person{firstname}[$a] cmp $person{firstname}[$b] +} 0 .. $#{ $person{firstname} }; foreach (@sorted) { print("firstname: ", $person{firstname}[$_], "\n"); print("lastname: ", $person{lastname }[$_], "\n"); print("city: ", $person{city }[$_], "\n"); print("\n"); }

    Or if you want to modify the structure itself,

    my @sorted = sort { $person{firstname}[$a] cmp $person{firstname}[$b] +} 0 .. $#{ $person{firstname} }; foreach (keys %person) { @{ $person{$_} } = @{ $person{$_} }[@sorted]; } foreach (0 .. $#{ $person{firstname} }) { print("firstname: ", $person{firstname}[$_], "\n"); print("lastname: ", $person{lastname }[$_], "\n"); print("city: ", $person{city }[$_], "\n"); print("\n"); }

    Notice how hard it is to extract the information you want? And how you have to assume the three arrays are of the same size? Those are indication that your data structure is poor.