Неумышленное добавление ключей к хешу при итерации - PullRequest
0 голосов
/ 14 сентября 2018

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

Я делаю это так

    foreach my $lat_key ( keys $lookup_cache_latlonhash ) {

        if ( ($lat > ($lat_key - .5)) && ($lat < ($lat_key + .5)) ) {

            foreach my $lon_key ( keys %{ $lookup_cache_latlonhash->{$lat_key}} ) {

                if ( ($lon > ($lon_key - .5)) && ($lon < ($lon_key + .5)) ) {

                    $country = $$lookup_cache_latlonhash{$lat_key}{$lon_key};
                    print "Approx match found: $lat_key $lon_key $country\n";
                    return $country;
                }
            }
        }
    }

Код работает, чтобы найти эти пары широта / долгота в пределах диапазона.Однако для каждой широты, которую он проходит, используя, когда он находит, что находится в диапазоне (первое вложенное условие), он добавляет его в хеш (предположительно keys %{ $goog_lookup_cache_latlonhash->{$lat_key}}), который не предназначен, добавляя бесполезные / пустые ключи к хешу:

$VAR1 = {
      '37.59' => {},
      '37.84' => {},
      '37.86' => {},
      '37.42' => {
                   '126.44' => 'South Korea/Jung-gu'
                 },
      '37.92' => {},
      '37.81' => {},
      '38.06' => {
                   '-122.53' => 'America/Novato'
                 },
      '37.8' => {},
      '37.99' => {},
      '37.61' => {},
       ...

Какой умный или хотя бы разумный способ сделать этот поиск?Так что я не случайно добавляю ключи в хеш, просто просматривая их?

Ответы [ 3 ]

0 голосов
/ 14 сентября 2018

Для этого можно использовать ключевое слово существующие .

Решение

use Data::Dumper;
$hash = {};
$hash{'alpha'} = 'yep';
$hash{'beta'} = 'this too';
if (exists $hash{'gamma'}) {
    print "Found gamma."
}
print Dumper(\%hash);
$hash{'gamma'} = 'added';
if (exists $hash{'gamma'}) {
    print "Gamma was updated.\n"
}
print Dumper(\%hash);

Пример вывода

$VAR1 = {
          'beta' => 'this too',
          'alpha' => 'yep'
        };
Gamma was updated.
$VAR1 = {
          'gamma' => 'added',
          'beta' => 'this too',
          'alpha' => 'yep'
        };
0 голосов
/ 14 сентября 2018

То, что вы испытываете, это авививификация .Особенность Perl - немного упростить работу с вложенными структурами.

Каждый раз, когда неопределенное значение разыменовывается, perl автоматически создает объект, к которому вы обращаетесь.

use Data::Dumper; 
my $hash = {}; if ($hash->{'a'}) {} #No auto-vivification because you're just checking the value   
keys %{$hash->{'b'}}; #auto-vivification because you're acting on the value (getting the keys of it) $hash->{b} 
print Dumper($hash);

Есть несколько способов избежать этого -

  1. Добавьте no autovivification в область действия, для которой вы хотите избежать этой функциональности
  2. Проверьте, определен ли существующий элемент, к которому вы обращаетесь, (существует ли он того типа, который вам нужен)

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

foreach my $lat_key (keys $lookup_cache_latlonhash) {
    if (($lat > ($lat_key - .5)) 
        && ($lat < ($lat_key + .5)) 
        && ref($lookup_cache_latlonhash->{$lat_key}) eq 'HASH')  #expecting a hash here - undefined or any non-hash value will skip the foreach
    {
        foreach my $lon_key (keys %{ $lookup_cache_latlonhash->{$lat_key}}) {
            if (($lon > ($lon_key - .5)) && ($lon < ($lon_key + .5))) {
                $country = $$lookup_cache_latlonhash{$lat_key}{$lon_key};
                print "Approx match found: $lat_key $lon_key $country\n";
                return $country;
            }
        }
    }
}
0 голосов
/ 14 сентября 2018

Помещенный

no autovivification;

в объеме.

...