Re: re-key a hash
by Ovid (Cardinal) on Aug 02, 2004 at 21:29 UTC
|
A hash is great if the data is sparsely populated, but if you make the keys sequential integers, why not go with an array?
my @array = @hash{ sort {$a <=> $b} keys %hash};
Incidentally, note that you're deleting hash elements while iterating over it. You're not supposed to do that.
Update: To keep a hash, try something like this:
my %hash2;
@hash2{ 0 .. (keys %hash)-1 } = map { $hash{$_} } sort {$a <=> $b} key
+s %hash;
It's really ugly, though :)
Update 2 ysth and Aristotle both caught me sleeping. Pay no attention to the man in the classical poet outfit.
| [reply] [d/l] [select] |
|
|
@hash2{ 0 .. (keys %hash)-1 } = @hash{ sort { $a <=> $b } keys %hash }
+;
I'm too lazy to verify, but I think you don't need to assign to a separate hash if you do it this way, either. The list should be assigned atomically once it is built completely.
Makeshifts last the longest.
| [reply] [d/l] [select] |
|
|
You are explicitly allowed to delete each element as you iterate; you ought not to make other changes (as this code does).
| [reply] |
|
|
| [reply] [d/l] [select] |
|
|
Re: re-key a hash
by shemp (Deacon) on Aug 02, 2004 at 21:41 UTC
|
You're losing some values because you're overwriting them before they get dealt with. The first key processed overwrites the value of $hash{0}. You could put the 'ordered' info into a different hash, and this wouldnt happen anymore.
Also, sort by default is a string comparison sort, so it goes like 1,10,11,12,13,14,15,16,17,18,19,2,20, etc, and negaitve values would come before the positive. Run this bit of code:
foreach my $i (sort (-20 .. 20)) {
print "$i\n";
}
To do a numeric sort, you need
sort {$a <=> $b} (keys %hashone)
In the end, i'd still agree with ovid about what you're doing! | [reply] [d/l] [select] |
Re: re-key a hash
by ysth (Canon) on Aug 02, 2004 at 22:17 UTC
|
First get a list of the values in sorted key order.
Note that @hash{ LIST } produces a list of the values
corresponding to the keys in list.
my @values = @hash{ sort { $a <=> $b } keys %hash };
Then clear your hash and assign the values using sequential keys:
%hash = ();
@hash{ 0..@values-1 } = @values;
or do it all in place without a temporary array:
@hash{ keys(%hash), 0..keys(%hash)-1 } = ((undef) x keys(%hash), @hash
+{ sort { $a <=> $b } keys %hash });
delete @hash{ grep !defined $hash{$_}, keys %hash };
Update:
@hash{ 0..keys(%hash)-1 } = delete @hash{ sort { $a <=> $b } keys %has
+h };
almost works, but the keys(%hash) on the left is evaluated after the hash has been empty :( | [reply] [d/l] [select] |
|
|
| [reply] |
|
|
The hoops are necessary to avoid preserving the old keys.
| [reply] |
Re: re-key a hash
by Aristotle (Chancellor) on Aug 02, 2004 at 23:08 UTC
|
%hash = (
0 .. keys( %hash ) - 1, @hash{ sort { $a <=> $b } keys %hash }
)[ map +( $_, $_ + keys %hash ), 0 .. keys( %hash ) - 1 ];
Makeshifts last the longest.
| [reply] [d/l] |
|
|
{
local $_ = keys( %h ) -1;
@h{ 0 .. $_ } = delete @h{ sort { $a<=>$b } keys %h };
}
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
| [reply] [d/l] |
|
|
{
my @key = sort { $a <=> $b } keys %h;
@h{ 0 .. $#key } = delete @h{ @key };
}
That seems like a cleaner separation of concerns. The symmetry of the second line here seems more pleasing and makes it more robust — it remains valid regardless of how the list of keys is generated.
Makeshifts last the longest.
| [reply] [d/l] |
|
|
Let the garbage collector do the deletes... I know, I know, it's not the problem spec!
my $count = 0;
%hash = map { $count++ => $a{$_} } sort { $a <=> $b } keys %hash;
| [reply] [d/l] |
|
|
| [reply] |
|
|
%hash = map { ($_, $hash{(sort keys %hash)[$_]}) } 0..keys(%hash)-1;
Caution: Contents may have been coded under pressure.
| [reply] [d/l] |
|
|
| [reply] |
|
|
| [reply] |
Re: re-key a hash ( Best (-: )
by ccn (Vicar) on Aug 02, 2004 at 22:08 UTC
|
$hash{-10} = 'bar';
$hash{-1} = 'foo';
$hash{12} = 'baz';
%hash =
map { (keys %hash) - 1 => delete $hash{$_} }
sort {$b <=> $a}
keys %hash;
print map {"$_ => $hash{$_}\n"} sort { $a <=> $b } keys %hash;
| [reply] [d/l] |
|
|
What's the point of your delete? You're assigning a completely new list to that hash in the end anyway.
It certainly doesn't seem like the "best" version to me, at least in terms of my usual metric: self-documentation.
Makeshifts last the longest.
| [reply] |
|
|
| [reply] [d/l] |
|
|
| [reply] |
Re: re-key a hash
by BrowserUk (Patriarch) on Aug 02, 2004 at 22:59 UTC
|
Yes, but it requires a temporary scalar.
my $n = keys( %hash ) -1;
@hash{ 0 .. $n } = delete @hash{ sort { $a<=>$b } keys %hash };
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
| [reply] [d/l] |
Re: re-key a hash (tye)
by tye (Sage) on Aug 03, 2004 at 01:07 UTC
|
use Algorithm::Loops 'MapCarMin';
%hash = MapCarMin {@_} [ 0 .. keys %hash ],
[ @hash{ sort {$a<=>$b} keys %hash } ];
or
%hash = map {
ref($_) && $_ == \$hash{''}
? ( delete $hash{''} )[1..0]
: ( ++$hash{''}, $_ )
} @hash{ sort {$a<=>$b} keys %hash }, \$hash{''};
( though this next one not working is quite clearly and simply a bug in Perl:
@hash{ 1..keys %hash } = delete @hash{
sort {$a<=>$b} keys %hash };
! :)
| [reply] [d/l] [select] |
|
|
$hash{keys %hash} = $_ for delete @hash{sort { $a<=>$b } keys %hash};
| [reply] [d/l] |
|
|
( though this next one not working is quite clearly and simply a bug in Perl
@hash{ 1..keys %hash } = delete @hash{
sort {$a<=>$b} keys %hash };
That was my thought until I realised that by the time the right-hand side of the assignment is evaluated, you've already deleted all the keys, so scalar keys %hash is zero. Whether you run the iterator from 0 as the OP asked or from 1 as your have it, it generates no keys and the values go in the bin.
Examine what is said, not who speaks.
"Efficiency is intelligent laziness." -David Dunham
"Think for yourself!" - Abigail
"Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
| [reply] [d/l] [select] |
|
|
/msg BrowserUk Turn on your chatterbox nodelet
My point (which includes a smiley) is that the left-hand side should be evaluated enough to give us full context (including how many slots we will be assigning into) before the right-hand side code is run in that context.
| [reply] |
|
|
|
|
|
|
|
|