2011-12-17 8 views
14

Как выбрать случайный хеш-ключ? Для my Flash+Perl card game я пытаюсь выбрать случайную карту из хэша, где ключи: «6 лопаты», «6 клубов» и т.д., как это:Выбор случайного ключа из хэша

my $card; 
my $i = 0; 
for $card (keys %{$user->{HAND}}) { 
    last if rand(++$i) < 1; 
} 
delete $user->{HAND}->{$card}; 
print "random card: $card\n"; 

Интересно, если это правильный путь или если это лучший способ.

+1

Не правильно вообще. «$ Card» в цикле 'for' является [« неявно локальным в цикле и восстанавливает прежнее значение после выхода из цикла »] (http://search.cpan.org/perldoc?perlsyn#Foreach_Loops). То есть '$ card' в вашем заявлении на печать является другой переменной, чем' $ card' в цикле 'for'. – mob

+0

Кроме того, факт, что вы генерируете новый номер каждый проход, искажает результат. – ikegami

ответ

16

Несколько более кратким:

my $random_value = $hash{(keys %hash)[rand keys %hash]}; 
+1

вы вдохновили меня, посмотрите «$ random_val_3» в моем посте. –

+0

приятный рефп! искусство perluscation perl !! – ennuikiller

+0

Спасибо, я был за моим $ random_key = (ключи% hash) [rand keys% hash]; –

14

Получить случайное значение из% хэша


  1. магазин ключи от вашего %hash в @hash_keys.
  2. генерировать случайное число между 0 и длину @hash_keys
  3. получить случайную запись из @hash_keys
  4. использовать приобретенный ключ, чтобы получить случайное значение от %hash

Пример фрагмента кода :

my %hash = ( 
    'stack' => 'overflow', 
    'face' => 'book', 
    'inter' => 'net' 
); 

## ALTERNATIVE 1 ## 
my @hash_keys = keys %hash; 

my $random_key = $hash_keys[rand @hash_keys]; 
my $random_value = $hash{$random_key}; 

## ALTERNATIVE 2 ## 
my $random_val_2 = (%hash)[1+2*int rand keys%hash]; # TIMTOWTDI 

## ALTERNATIVE 3 ## 
my $random_val_3 = [@_=%hash]->[1|[email protected]_];   # TIMTOWTDI 
+0

Что делает «1 |» в последней строке делать? –

+0

@AlexanderFarber это побитовое ИЛИ, убедившись, что мы получаем только нечетные числа внутри скобок. '1 | 2 => 3', '1 | 0 => 1', '1 | 1 => 1'. Он всегда будет устанавливать младший значащий бит в целое число: 1. –

+0

@refp: Я считаю, что это всегда возвращает одно и то же значение при первом вызове: 'perl -Mstrict -wE 'my% hash = map {$ _ => $ _} 1..100; скажем ((@ _ =% hash) [1 | rand @ _]) для 1..10; '' – Zaid

1

Вот еще один способ (демонстрируя, как выбрать случайный элемент из списка неизвестной длины):

my $cards; 
my $chosen; 
while (my $card = each %{$user->{HAND}}) { 
    $chosen = $card if rand(++$cards) < 1; 
} 
+0

О, теперь я понимаю: у меня не должно быть «последнего» в моем исходном коде –

+0

Правильно, $ selected должен быть сброшен более одного раза. – ysth

Смежные вопросы