Метод перетасовки в Perl List::Util. Как расшевелить?

Я склонен использовать метод перемешивания, чтобы рандомизировать порядок элементов списка. Например, вот код, который путает роли для небольшой игры:

 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?


person ado    schedule 10.09.2013    source источник


Ответы (1)


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;

Однако вы пропускаете роли, которые сопоставляются с нулем. Поскольку этой информации больше нет в массиве ролей, ее нельзя воссоздать.

person amon    schedule 10.09.2013
comment
Я изо всех сил пытаюсь расширить index-shuffle до аналогии с жареным яйцом :) - person Zaid; 10.09.2013
comment
разрушение белка с помощью нагревания является классическим примером односторонних операций в биологии. Во время нагревания связи, поддерживающие пространственную структуру белка, разрываются и случайным образом перестраиваются. Информация об исходной структуре при этом теряется, а свойства протеина заметно изменяются (в случае яиц: цвет и консистенция меняются от блестяще-прозрачного до твердо-белого). - person amon; 10.09.2013
comment
Ваше объяснение предназначено для перетасовки фактического списка (яичница-болтунья в кулинарных терминах), но показанный вами трюк с перетасовкой индексов, по сути, позволяет вам увидеть, как выглядит яйцо, когда оно взбито, без фактического приготовления яйца. Я имел в виду, что было бы здорово увидеть аналогию с яйцом, расширенную для представления примера перетасовки индексов :) - person Zaid; 10.09.2013