I have a hash of string IDs. What is the best way to shuffle the IDs?
As an example, my hash assigns the following IDs:
this => 0
is => 1
a => 2
test => 3
Now I'd like to randomly shuffle that. An example outcome would be:
this => 1
is => 0
a => 3
test => 2
You could use the shuffle
method in List::Util
to help out:
use List::Util qw(shuffle);
...
my @values = shuffle(values %hash);
map { $hash{$_} = shift(@values) } (keys %hash);
A hash slice would be the clearest way to me:
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/shuffle/;
use Data::Dumper;
my %h = (
this => 0,
is => 1,
a => 2,
test => 3,
);
@h{keys %h} = shuffle values %h;
print Dumper \%h;
This has a drawback in that huge hashes would take up a lot of memory as you pull all of their keys and values out. A more efficient (from a memory standpoint) solution would be:
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/shuffle/;
use Data::Dumper;
my %h = (
this => 0,
is => 1,
a => 2,
test => 3,
);
{ #bareblock to cause @keys to be garbage collected
my @keys = shuffle keys %h;
while (my $k1 = each %h) {
my $k2 = shift @keys;
@h{$k1, $k2} = @h{$k2, $k1};
}
}
print Dumper \%h;
This code has the benefit of only having to duplicate the keys (rather than the keys and values).
The following code doesn't randomize the values (except on Perl 5.8.1 where the order of keys is guaranteed to be random), but it does mix up the order. It does have the benefit of working in place without too much extra memory usage:
#!/usr/bin/perl
use strict;
use warnings;
use List::Util qw/shuffle/;
use Data::Dumper;
my %h = (
this => 0,
is => 1,
a => 2,
test => 3,
);
my $k1 = each %h;
while (defined(my $k2 = each %h)) {
@h{$k1, $k2} = @h{$k2, $k1};
last unless defined($k1 = each %h);
}
print Dumper \%h;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With