Обновление значения в хэше массива или хэшей

#perl #hashmap

#perl #hashmap

Вопрос:

Я инициализирую хэш-таблицу следующим образом:-

 my %AllCountStats = ();
foreach my $Log (@LogList) {
    foreach my $Func (keys %AllFuncNames) {
        push @{$AllCountStats{$Log}}, {Func=>$Func,Count=>0};
    }
}
print Dumper (%AllCountStats);
  

Вывод дампера выглядит следующим образом:-

 $VAR1 = {
    'log.1' => [
        {
            'Count' => 0,
            'Func' => 'Function A'
        },
        {
            'Func' => 'Function B',
            'Count' => 0
        },
    }
    'log.2' => [
        {
            'Count' => 0,
            'Func' => 'Function A'
        },
        {
            'Count' => 0,
            'Func' => 'Function X'
        },
    };
  

Теперь мне нужно выполнить итерацию по хэшу массива хэшей и хирургически обновить значения Count для каждой функции. Используя приведенный выше пример, какую команду мне выполнить, чтобы обновить log.1 в Func=Function Значение Count до чего-то нового (т. Е. Не 0)? Вот пример того, где / как я пытаюсь выполнить обновление…

 foreach $Log (@LogList) {
    foreach (sort {$a->{SCmdLineNum} <=> $b->{SCmdLineNum}} @{$SweepStats{$Log}}) {
        $SCmd = $_->{SCmd};
        my $inner = $AllCountStats{$Log}{$SCmd}{Count};
        $inner->{$_}   for keys %$inner;
    }
}
  

Но это не работает. Когда $inner фактически становится $AllCountStats{log .1} {Функция B} {Count}, как я могу аккуратно обновить его значение Count?

Комментарии:

1. Откуда %SweepStats берутся? Пожалуйста, попробуйте отредактировать код, чтобы мы могли запустить его и воспроизвести вашу проблему. Что вы подразумеваете под «не работает»?

2. Привет, @choroba, тебе действительно не нужно беспокоиться о%SweepStats — главный вопрос заключается в том, как хирургически обновить поля подсчета в %AllCountStats . Когда я пытаюсь выдать этот $inner-> {$_} , он сообщает, что предыдущая строка является недопустимой ссылкой на хэш, поэтому я предполагаю, что она отформатирована неправильно.

3. Re » вам действительно не нужно беспокоиться о%SweepStats «, хорошо, верно, но нам нужно знать, какой Count из них вы пытаетесь увеличить для данного элемента @{$SweepStats{$Log}} .

4. Совет: это sort бесполезно. Ничто в цикле не заботится о порядке посещения элементов.

Ответ №1:

$AllCountStats{$Log} это ссылка на массив, но вы рассматриваете его как ссылку на хэш.

Это

 $AllCountStats{$Log}{$SCmd}{Count}
  

должно быть

 $AllCountStats{$Log}[$i]{Count}
  

Неясно, какое значение вы хотите $i . Мы вернемся к этому.


Далее, следующее не имеет смысла:

 my $inner = $AllCountStats{$Log}[$i]{Count};
$inner->{$_}   for keys %$inner;
  

$inner это просто число, а не ссылка на хэш. Вы хотите

 my $inner = $AllCountStats{$Log}[$i]
  $inner->{Count};
  

или просто

   $AllCountStats{$Log}[$i]{Count};
  

Вернуться к $i . Мое лучшее предположение заключается в том, что вы хотите увеличить Count значение записи, Function значение которой равно $SCmd .

 for my $log_name (@LogList) {
   my $log = $AllCountStats{$log_name};

   for my $stats_rec (@{$SweepStats{$Log}}) {  # Useless sort removed.
      my $SCmd = $stats_rec->{SCmd};
      for my $log_rec (@$log) {
           $log_rec->{Count} if $log_rec->{Function} eq $SCmd;
      }
   }
}
  

Если это так, было бы проще, если бы вы построили %AllCountStats так, чтобы это выглядело

 my %AllCountStats = (
   'log.1' => {
       'Function A' => 0,
       'Function B' => 0,
   },
   ...
);
  

Тогда все, что вам нужно, это

 for my $log_name (@LogList) {
   my $log = $AllCountStats{$log_name};
   for my $stats_rec (@{$SweepStats{$Log}}) {
        $log->{ $stats_rec->{SCmd} };
   }
}
  

Комментарии:

1. спасибо за предложение! Ваши предположения точны, и ваша рекомендация сработала. Я прошу прощения за то, что у меня не было более чистого исходного сообщения, но было больно извлекать суть проблемы (много сложных журналов, проприетарные детали, тысячи функций и т. Д., Но Нужно было изменить только количество).

Ответ №2:

Пожалуйста, посмотрите следующий фрагмент кода (должно быть легко понять)

 use strict;
use warnings;
use feature 'say';

use Data::Dumper;

my $log   = 'log.1';
my $func  = 'Function A';
my $count = 5;

my %AllCountStats = (
    'log.1' => [
        {
            'Count' => 0,
            'Func' => 'Function A'
        },
        {
            'Func' => 'Function B',
            'Count' => 0
        }
    ],
    'log.2' => [
        {
            'Count' => 0,
            'Func' => 'Function A'
        },
        {
            'Count' => 0,
            'Func' => 'Function X'
        }
    ]
);

for ( @{$AllCountStats{$log}} ) {
    $_->{'Count'} = $count if $_->{'Func'} eq $func;
}

say Dumper(%AllCountStats);
  

Комментарии:

1. @’Polar Bear’ большое спасибо — это именно то, что мне нужно было сделать, и оно работает как надо!

Ответ №3:

Второй уровень структуры, похоже, представляет собой массив, а не хэш. Для этого нужны квадратные скобки.

В %AllCountStats , вы храните числа под ключом «Count». Это число сохраняется в $inner , и затем вы пытаетесь разыменовать его как хэш.

Вместо этого увеличьте значение напрямую:

   $AllCountStats{$Log}[$SCmd]{Count}
  

Комментарии:

1. (Я сомневаюсь $SCmd , что это число. Я думаю, что это еще не все)

2. Правильный $ SCmd на самом деле является сложной текстовой строкой — необходимо использовать index() != -1 для проверки совпадений и т. Д.

3. Тогда я не понимаю, как вы хотите использовать сложную текстовую строку для индексации в массив.