I just wanted to add another followup with a couple more possible solutions. I'll discuss the virtues and weaknesses as we go.

First, the each method:

use strict; use warnings; my %hash = ( one => 1, two => 2, three => 3, four => 4, five => 5 ); my $priority_key = 'three'; sub prioritize { my( $href, $find ) = @_; my @prioritized_keys; while( my( $key, $value ) = each %{$href} ) { if( $key ne $find ) { push @prioritized_keys, $key; } else { unshift @prioritized_keys, $key; } } return \@prioritized_keys; } my @keyset = @{ prioritize( \%hash, $priority_key ) }; print "@keyset\n";

Ok, the good: This iterates through the key list one time, so it's an O(n) operation. Also, all the work being done on @prioritized_keys is done "at the ends" of the array via push and shift, which is faster than splicing the middle of an array. The bad: It's probably less efficient to while{} and each ones way through the key/value pairs, ignoring the values, just to build up a key list. On the other hand, you're only going through the list once, unlike the grep solution. To summarize, this is O(n), but each iteration may be more expensive than my O(2n) solution proposed earlier.

Ok, now for another solution using splice.

use strict; use warnings; my %hash = ( one => 1, two => 2, three => 3, four => 4, five => 5 ); my $priority_key = 'three'; sub prioritize { my( $href, $find ) = @_; my @keyring = keys %{$href}; foreach my $idx ( 0 .. $#keyring ) { next unless $keyring[ $idx ] eq $find; unshift( @keyring, splice( @keyring, $idx, 1 ) ); last; } return \@keyring; } my @keyset = @{ prioritize( \%hash, $priority_key ) }; print "@keyset\n";

The good: Unlike the grep solution, as soon as you've found the priority key, the prioritization loop exits. That means there's a worst case of O(n) for the prioritization loop, and a best case of one iteration, with an average case of O(n/2), assuming the completely random nature of keys in list context yields an average condition. The bad; you are performing two O(n) (worst case) operations; one is creating the key list using keys, and the second is where you find the priority key. One of the loops is performed internally, probably very quickly (that's the keys loop), and the second has the potential of terminating pretty early on, if the priority key is found right away, but there's an equal potential that the second loop will terminate later on. But at very least, unlike grep, the second loop will terminate as soon as possible. On the other hand, there's still more bad news: this solution splices the middle of an array, which is more expensive than pushing or unshifting, possibly even resulting in another O(n) operation (I'm not clear on that, without full knowlege of how splice is implemented internally).

Without benchmarking, I couldn't say whether the grep solution, the each solution, or the splice solution is the best.

I guess we'll just have to test and see, though unless the hash is huge, it doesn't really matter anyway.


Dave


In reply to Re: Pulling an item to the front of the list by davido
in thread Pulling an item to the front of the list by Tanktalus

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.