in reply to Pulling an item to the front of the list

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