迭代时无意中将键添加到散列
Unintentionally adding keys to hash while iterating
我正在遍历指向 key/value 对 longitudes/cities 的纬度键散列的散列缓存。我试图找到 latitudes/longitudes 的近似匹配项,这些匹配项与已经查找的内容足够接近并且在散列中。
我是这样做的
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;
}
}
}
}
该代码用于在范围内找到这些 lat/lon 对。然而,对于它循环使用的每个纬度,当它确实发现它在范围内(第一个嵌套条件)时,它会将它添加到散列(可能是 keys %{ $goog_lookup_cache_latlonhash->{$lat_key}}
),这不是预期的,添加 useless/empty 键到哈希:
$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' => {},
...
执行此查找的聪明或至少是理智的方法是什么?所以我不是无意中通过查找将键添加到哈希中?
放
no autovivification;
范围内。
您可以为此使用 exists keyword。
解决方案
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'
};
您遇到的是 auto-vivification。 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);
有几种方法可以避免这种情况 -
- 在你想避免的范围内添加
no autovivification
功能
- 检查您正在访问的项目是否已定义
或存在(并且是您需要的类型)
我推荐第二个,因为它有助于养成检查代码数据结构是否正确的习惯,并使调试更容易。
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;
}
}
}
}
我正在遍历指向 key/value 对 longitudes/cities 的纬度键散列的散列缓存。我试图找到 latitudes/longitudes 的近似匹配项,这些匹配项与已经查找的内容足够接近并且在散列中。
我是这样做的
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;
}
}
}
}
该代码用于在范围内找到这些 lat/lon 对。然而,对于它循环使用的每个纬度,当它确实发现它在范围内(第一个嵌套条件)时,它会将它添加到散列(可能是 keys %{ $goog_lookup_cache_latlonhash->{$lat_key}}
),这不是预期的,添加 useless/empty 键到哈希:
$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' => {},
...
执行此查找的聪明或至少是理智的方法是什么?所以我不是无意中通过查找将键添加到哈希中?
放
no autovivification;
范围内。
您可以为此使用 exists keyword。
解决方案
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'
};
您遇到的是 auto-vivification。 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);
有几种方法可以避免这种情况 -
- 在你想避免的范围内添加
no autovivification
功能 - 检查您正在访问的项目是否已定义 或存在(并且是您需要的类型)
我推荐第二个,因为它有助于养成检查代码数据结构是否正确的习惯,并使调试更容易。
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;
}
}
}
}