如何在哈希中混洗值?

时间:2011-07-13 19:06:01

标签: perl shuffle

我有一个字符串ID的哈希值。什么是洗牌的最佳方法?

例如,我的哈希值分配了以下ID:

this => 0
is => 1
a => 2 
test => 3

现在我想随机改变它。一个示例结果将是:

this => 1
is => 0
a => 3
test => 2

2 个答案:

答案 0 :(得分:7)

您可以使用List::Util中的shuffle方法提供帮助:

use List::Util qw(shuffle);

...

my @values = shuffle(values %hash);
map { $hash{$_} = shift(@values) } (keys %hash);

答案 1 :(得分:4)

哈希切片对我来说是最清晰的方式:

#!/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;

这有一个缺点,即当你拉出所有键和值时,巨大的哈希会占用大量内存。更有效(从内存的角度来看)解决方案是:

#!/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;

此代码的好处是只需复制键(而不是键和值)。

以下代码不会随机化值(Perl 5.8.1除外,其中键的顺序保证是随机的),但它会混淆顺序。它确实具有在没有太多额外内存使用的情况下正常工作的好处:

#!/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;