2012-01-25 3 views
2

У меня есть то, что похоже на хэш хеша массива хэшей. Я пытаюсь тянуть некоторые значения, и я в тупике (это способ глубже, чем я хотел бы пойти со структурой. Похоже, что это .....Итерация над сложной структурой данных

%htest = (
    8569 => { 
    4587 => [ 
      { 
      date=> "2011-01-15", 
      approved=> 1, 
      }, 
      { 
      date=> "2011-01-12", 
      approved=> 1, 
      }, 
      ], 
    1254 => [ 
      { 
      date=> "2011-01-12", 
      approved=> "", 
      }, 
      { 
      date=> "", 
      approved=> 1, 
      }, 
      ], 
     }, 
); 

Попытку перебрать эту вещь давая мне массивную головную боль.Я пытаюсь получить доступ к количеству элементов под вторым значением хэш-функции (4587 и 1254). Число тех элементов, где одобрено = «1», и количество элементов, в которых дата содержит значение.

Если бы я мог перебрать их, я уверен, что смогу впихнуть то, что мне нужно в менее сложную структуру, но до сих пор я в недоумении.

Я получил это далеко ...

while (my ($id, $surveyhash) = each %{ $htest{'8569'} }){ 
    print "$enumid = $subhash\n"; 
    print Dumper $subhash."\n"; 
} 

Это дает мне «4587» и «1254», но пытается сделать самосвал на $ Subhash просто дает мне ....

4587 = ARRAY(0x9a9ffb0) 
$VAR1 = 'ARRAY(0x9a9ffb0) 
'; 
1254 = ARRAY(0x9a91788) 
$VAR1 = 'ARRAY(0x9a91788) 
'; 

Любой идее, как перебрать это уродство? Джени

ответ

4

Ваша структура имеет опечаток, вам нужно запятые между внутренним и хешей скобку в конце (а не фигурной скобкой)

После того, как вы это исправить вы можете использовать что-то вроде этого:

my $approved = 0, my $date_has_value = 0; 
while (my ($k,$vref) = each %htest) { 
    while (my ($k,$v) = each %$vref) { 
     # Now you're inside the inner hash, so there will be 2 iterations 
     # with $k 4587 and 1254 
     foreach my $item (@$v) { 
      # Now each $item is a reference to the innermost hashes 
      $approved++ if $item->{approved} == 1; 
      $date_has_value++ if $item->{date}; 
     } 
    } 
} 
+0

OMG xpapad, какой быстрый ответ! Я исправлял это, когда вы отвечали. –

+1

@JaneWilkie вы можете использовать 'eq' вместо' == 'в' $ approved ++, если $ item -> {approved} == 1; ', чтобы избежать аргументации" "не является числовым ... предупреждением. Похоже, что вы одобрили не числовое значение. Кроме этого, код выше отличный. – jchips12

+0

Это работает как CHAMP! Проголосовать xpapad UP! ПУТЬ! –

2

Вот довольно явная итерация, которые должны помочь вам начать работу

my ($num_approved, $num_date) = (0, 0); 

# outer hash 
while (my ($ka, $va) = each %htest) 
{ 
    # inner hash 
    while (my ($kb, $vb) = each %{$va}) 
    { 
    # each hash inside the array 
    foreach my $h (@{$vb}) 
    { 
     $num_approved += ${$h}{"approved"} == 1; 
     $num_date  += length(${$h}{"date"}) > 0; 
    } 
    } 
} 
+0

Голосование за учебники. Клянусь, 2012 год - год, когда мне стало лучше. JW –

2

случаи совпадения Counting можно сделать с помощью «скалярной Grep».

my ($approved, $date_has_value) = (0, 0); 

for my $v1 (values %htest) { 
    for my $v2 (values %$v1) { 
     $approved  += scalar grep { $$_{approved} eq '1' } @$v2; 
     $date_has_value += scalar grep { $$_{date}  ne '' } @$v2; 
    } 
} 
+1

Хотелось бы заметить, что здесь не требуется «скаляр». '+ =' дает скалярный контекст сам по себе. (Я оставил бы его, хотя бы дать новым программистам Perl указание на то, что происходит.) –

+1

Да, не все согласны с этим. Некоторые люди говорят, что оставить «скаляр» в том, что он делает более ясным, что происходит, и менее хрупким по отношению к выражению, перемещаемому в контекст списка, и в любом случае он не компилируется ни к чему; другие люди говорят, что если он ничего не делает, то вытащите его. – zgpmax

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