2011-07-13 9 views
5

私は文字列IDのハッシュを持っています。 IDをシャッフルする最善の方法は何ですか?ハッシュ値をシャッフルするにはどうすればいいですか?

例として、私のハッシュは以下のIDが割り当てられます。

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

を今、私はランダムにそれをシャッフルしたいと思います。例の結果は次のようになります。

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

あなたは常にそれらのいずれかから選択ランダムにし、別のハッシュのハッシュを作成し、可能性があり、無効コンテキストで) – hemlocker

答えて

7

あなたが手伝ってList::Utilshuffle方法を使用することができます。

use List::Util qw(shuffle); 

... 

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

'map'です憎悪 –

+0

これは単なるスタイルの問題ですか、それとも技術的な異論はありますか? (ちょっと好奇心) – Mat

+1

'map'がリストを返すと(空のコンテキストでさえ)本当の問題でした。最近は単なるスタイルの問題です。私のように、働くための機能の副作用に頼るのは忌み嫌われている人がいます。特に、副作用を使用しないような短い構文を使用している場合は、次のようになります。 '$ hash {$ _} =キー%hashの値をシフトします;' –

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; 
関連する問題