在Perl的List :: Util的"shuffle"方法.如何"洗头"?

ado*_*ado 1 perl shuffle

我倾向于使用shuffle方法随机化列表元素的顺序.例如,这是一个代替小游戏角色的代码:

 sub assign_roles {
       my ( $role_num_map ) = @_;
       my @roles;
       for my $role ( keys %$role_num_map ) {
         next if $role_num_map->{$role} == 0;
         push @roles, $role for ( 1 .. $role_num_map->{$role} );
       }
       my @shuffled_roles = shuffle @roles;
 }
Run Code Online (Sandbox Code Playgroud)

我的问题是,"洗牌"如何使订单随机化?它使用什么方法? 如何从@shuffled_roles返回到$ role_num_map?

amo*_*mon 7

shuffle随机化订单.因此,这种操作无法恢复(就像你不能把一个煎蛋放入冰箱里一样).但我们可以使用一个技巧:改组索引而不是值:

my @items = 'a' .. 'z';  # things we want to shuffle
my @shuffled_idxs = shuffle 0 .. $#items;
my @shuffled = @items[@shuffled_idxs]; # using a slice to do the actual shuffling
Run Code Online (Sandbox Code Playgroud)

从中@shuffled_idxs,我们可以创建一个允许反向查找的数组:

my @reverse_idxs;
$reverse_idxs[$shuffled_idxs[$_]] = $_ for 0 .. $#shuffled_idxs;

# now we can use a slice to reverse the shuffling:
my @reversed = @shuffled[@reverse_idxs];
Run Code Online (Sandbox Code Playgroud)

当我们打印出来@items@shuffled,和@reversed,我们可以获得以下输出:

abcdefghijklmnopqrstuvwxyz
hyaxruvnogekdzjmbpilstcqfw
abcdefghijklmnopqrstuvwxyz
Run Code Online (Sandbox Code Playgroud)

这适用于数组.你的例子有点不同,因为你有像这样的序列

a b b b c c
Run Code Online (Sandbox Code Playgroud)

而你想做哈希{ a => 1, b => 3, c => 2 }.这可以在没有洗钱的情况下完成,使用正常计数代替:

my %reversed;
$reversed{$_}++ for @shuffled_roles;
Run Code Online (Sandbox Code Playgroud)

但是,您跳过映射到零的角色.由于此信息不再出现在角色阵列中,因此无法重新创建.