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

Hello all,

I have a hash with the key being the field name and the value being the order in which the field is to be displayed.....like below:

%order = ( DATE => '1', CPP => '2', ESN => '3', BTS => '4' );

I'm receiving an array that would look something like this:

@to_be_ordered = qw(CPP BTS DATE);

What I'd like to do, is sort @to_be_ordered based on the ordering scheme defined in %order. Notice that ESN is missing....I'd like to be able to keep it in order even if some are missing.

I've looked at the sort and map functions and can't quite figure out how to manipulate the array into the way I need it.

Any help is appreciated,

Kevin

Replies are listed 'Best First'.
Re: Sorting an array based on hash values
by FoxtrotUniform (Prior) on Jun 20, 2002 at 17:16 UTC
    my @sorted = sort {$order{$a} <=> $order{$b}} @to_be_ordered;

    This is not well-behaved for elements of @to_be_ordered that aren't present in %order.

    --
    The hell with paco, vote for Erudil!
    :wq

      If you want values in @to_be_ordered that are not in %order to be put at the end of the list, you might try something like this:
      my @sorted = ((sort {$order{$a} <=> $order{$b}} grep {exists $order{$_}} @to_be_ordered), grep {not exists $order{$_}} @to_be_ordered);
      Of course, this runs through @to_be_ordered twice, which is inefficient. So you might use two temporary arrays:
      my (@exists, @not_exists); push @{exists $order{$_} ? \@exists : \@not_exists }, $_ for @to_be_or +dered; my @sorted = ((sort {$order{$a} <=> $order{$b}} @exists), @not_exists) +;

      -- Mike

      --
      just,my${.02}

Re: Sorting an array based on hash values
by bronto (Priest) on Jun 21, 2002 at 08:26 UTC

    If values are non-repeated, as it appears in %order, you could also use a reversed version of the hash to do the sort. Please note that this doesn't hold if there are repeated values in %order!

    In that less general hypothesis, you could do:

    my @ordered ; my %r_order = reverse %order ; # %r_order is now ( 1 => 'DATE', 2=> 'CPP'... # ...and so on. { # slice %order in @temp # (the following two lines could be compacted into one # but... KISS :-) my @temp = sort { $a <=> $b } @order{@to_be_ordered} ; @ordered = @r_order{@temp} ; # @temp will now disappear :-) } # Now @ordered contains the sorted list based on # @to_be_ordered, so... &do_what_you_want_with(@ordered) ;

    That should work.

    Ciao!
    --bronto