2017-02-01 18 views
0

Существует много ссылок относительно check if a hash is empty. Я попробовал их все в следующем сценарии:Почему проверка того, что хеш пуст, терпит неудачу?

use strict; 
use warnings; 
use Data::Dumper; 
    $Data::Dumper::Sortkeys = 1; 

# Signals come... 
my %items = (
    item_1 => {signal_1 => 'up', 
       signal_2 => 'down', 
       signal_3 => 'up', 
       }, 
    item_2 => {signal_1 => 'down', 
       }, 
    item_3 => {signal_1 => 'up', 
       signal_3 => 'down', 
       signal_4 => 'down', 
       signal_5 => 'down', 
       }, 
); 

# ... and signals go: 
delete $items{'item_2'}->{'signal_1'}; 
# and sometimes all signals are gone from an item: 
print Dumper(\%items); 
# in that case we would like the signal count to show 0 (zero). 
my %signals; 
foreach my $item (sort keys %items){ 
    #$signals{$item} = 0; 
    foreach my $signal (sort keys %{$items{$item}}){ 
    if (not %{$items{$item}}) {print "HERE\n"; $signals{$item} = 0} 
    elsif($items{$item}->{$signal} eq 'up') {$signals{$item}++} 
    elsif($items{$item}->{$signal} eq 'down'){$signals{$item}--} 
    } 
} 
# unfortunately the item disappears completely! 
print Dumper(\%signals); 

Кажется, что итератор полностью пропускает пустой хеш. Мой единственный способ получить правильный результат состоял в том, чтобы инициировать каждый счетчик до нуля (закомментирован) и позволить ему увеличивать/уменьшать непустые хэши.

Почему это ... ???

+1

@Toto Я думаю, вопрос в том, почему нет 'item_2 => 0'. – simbabque

+0

@simbabque: ОК, я неправильно понял :( – Toto

+0

Если есть X ключей, для которых итерации, то есть X итераций цикла. Да, это применимо даже тогда, когда X равно нулю. Ваш «обходной путь» на самом деле является правильным способом справляясь с ситуацией. – ikegami

ответ

4

Если в хеше нет ключей, то keys возвращает пустой список (). Когда вы повторяете с foreach над пустым списком, тело цикла никогда не будет вызываться. Таким образом, ваш print "HERE" никогда не будет достигнут. Это верно.

foreach (()) { 
    print "foo"; 
} 

__END__ 
(no output) 

в Perl автоматически вивификация создает значения хэша для вас, когда вы используете их в первый раз, и значения начинают как 0, когда вы делаете математику на них. Вот почему вы можете добавлять и извлекать из них в свою петлю внутри условий.

Чтобы заставить его работать, вы уже поступили правильно с вашей пропущенной линией.

foreach my $signal (sort keys %{$items{$item}}){ 
    $signals{$item} = 0; 
    if (... 

Теперь вы инициализировать каждый ключ к 0 первой. Это делает то же самое, что и неявно, как описано выше, он просто делает это каждый раз.