1

我倾向于使用 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;
 }

我的问题是,“洗牌”如何随机化订单?它使用什么方法? 我怎样才能从 @shuffled_roles 回到 $role_num_map ?

4

1 回答 1

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

从 中@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];

当我们打印出@items@shuffled@reversed时,我们可以得到以下输出:

abcdefghijklmnopqrstuvwxyz
hyaxruvnogekdzjmbpilstcqfw
abcdefghijklmnopqrstuvwxyz

这适用于数组。你的例子有点不同,因为你有像

a b b b c c

并且您想制作哈希{ a => 1, b => 3, c => 2 }。这可以在不改组的情况下完成,而是使用正常计数:

my %reversed;
$reversed{$_}++ for @shuffled_roles;

但是,您会跳过映射为零的角色。由于此信息不再存在于角色数组中,因此无法重新创建。

于 2013-09-10T07:46:59.230 回答