我有下面的散列结构。
$VAR1 = {
'USA' => {
'Alabama' => {
'ISO3' => 'ISO3:3166-2:US',
'ISO2' => 'ISO2:4166-23:US',
'UNI' => 'UNIABR-A',
'UNDP' => 'UNDP-ZXC-1',
'FAOSTAT' => 'STAT20.98',
'GAUL' => 'UL-SD-20/40'
},
'Washington' => {
'ISO3' => 'ISO3:40-166-2:US',
'ISO2' => 'ISO2:30-23:US',
'UNI' => 'UNIISO-B',
'UNDP' => 'UNDP-YXC-2',
'FAOSTAT' => 'STAT30.98.78',
'GAUL' => 'UL-SD-30/60'
}
}
};我想要实现的是迭代上面的散列,并在散列“is 2:4166-23:US”中获得值的statename和country名称。我想做的是:
我可以通过下面的代码获得所需的输出。
my $find = "ISO2:4166-23:US";
my $statename;
while ( my ($country, $states) = each (%$VAR1) ) {
while (my ($states, $otherkeys) = each (%$states) ) {
while (my ($otherkeys, $value) = each %$otherkeys) {
$statename = $states if ($value eq $find);
}
}
}
print "State name for value [$find] is :: $statename \n"; ### Output : Alabama有什么办法让我-
如果top-level key等于ISO2:4166-23:US,则获取$value "USA“和second-level key "Alabama”。我所知道的是我需要获得输出的哈希内部值,与我的搜索值对应的键并不重要。
使用上面哈希中的一行grep命令?
任何指向正确方向的指针都是有用的。谢谢。
发布于 2020-10-07 21:35:01
你的变量名字很差。重用$states作为州名吗?唉哟。
my $find = "ISO2:4166-23:US";
my $found_state_name;
while ( my ($country_name, $states) = each(%$VAR1) ) {
while (my ($state_name, $state) = each(%$states) ) {
while ( my ($key, $value) = each(%$state) ) {
if ($value eq $find) {
$found_state_name = $state_name;
}
}
}
}现在,这将是很高兴停止搜索,一旦你发现一个结果。我们不能在仍然使用each的时候做到这一点(因为它会在那些散列上搞砸以后的each)。
my $find = "ISO2:4166-23:US";
my $found_state_name;
FIND:
for my $country_name (keys(%$VAR1)) {
my $country = $VAR1->{$country_name};
for my $state_name (keys(%$country)) {
my $state = $country->{$state_name};
for my $key (keys(%$state)) {
if ($state->{$key} eq $find) {
$found_state_name = $state_name;
last FIND;
}
}
}
}除了获取值外,我们从不使用$country_name或$key。
my $find = "ISO2:4166-23:US";
my $found_state_name;
FIND:
for my $states (values(%$VAR1)) {
for my $state_name (keys(%$states)) {
my $state = $country->{$state_name};
for my $value (values(%$state)) {
if ($value eq $find) {
$found_state_name = $state_name;
last FIND;
}
}
}
}如果您知道您正在寻找一个ISO2值,这将简化为以下内容:
my $find = "ISO2:4166-23:US";
my $found_state_name;
FIND:
for my $states (values(%$VAR1)) {
for my $state_name (keys(%$states)) {
my $state = $states->{$state_name};
if ($state->{ISO2} eq $find) {
$found_state_name = $state_name;
last FIND;
}
}
}你想用grep,嗯?因为您因此需要一个州名,所以我们需要grep一个州名列表。
my @state_names = ...;
my ($found_state_name) =
grep { ... }
@state_names;我们可以使用以下方法获得状态名称列表
my @state_names =
map { keys(%$_) }
values(%$VAR1);但这还不足以进行检查。(现在,我将假设只需要检查ISO2属性。)
my @state_names =
map { keys(%$_) }
values(%$VAR1);
my ($found_state_name) =
grep { $VAR1->{???}{$_}{ISO2} eq $find }
@state_names;有两种解决办法。你可以和乡村州对一起工作。
my @country_state_name_pairs =;
map {
my $country_name = $_;
map { [ $country_name, $_ ] }
keys(%{ $VAR1->{$country_name} )
}
keys(%$VAR1);
my ($found_state_name) =
map { $_->[1] }
grep {
my ($country_name, $state_name) = @$_;
$VAR1->{$country_name}{$state_name}{ISO2} eq $find
}
@country_state_name_pairs;或者,您可以创建一个简单的状态列表并搜索它。
my @states_with_name =
map { [ $_, $VAR1->{$_} ] }
values(%$VAR1);
my ($found_state_name) =
map { $_->[0] }
grep { $_->[1]{ISO2} eq $find }
@states_with_name;注意阻止我们合并这两个语句。
my ($found_state_name) =
map { $_->[0] } # Get the state name.
grep { $_->[1]{ISO2} eq $find } # Filter out undesireable states.
map { [ $_, $VAR1->{$_} ] } # $state_name => [ $state_name, $state ]
values(%$VAR1); # Get the countries.最后一个不算太糟!
最后,有两种方法可以修改上面的每个字段来搜索所有字段,而不仅仅是ISO2)。(我将只对上述两种解决方案中的后一种进行修改。)
my ($found_state_name) =
map { $_->[0] } # Get the state name.
grep { # Filter out undesireable states.
grep { $_ eq $find } # Filter out undesireable properties of the state.
values(%{ $_->[1] }) # Get the state's property values.
}
map { [ $_, $VAR1->{$_} ] } # $state_name => [ $state_name, $state ]
values(%$VAR1); # Get the countries.或
my ($found_state_name) =
map { $_->[0] } # Get the state name.
grep { $_->[1] eq $find } # Filter out undesireable states.
map { # $state_name => multiple [ $state_name, $value ]
my $state_name = $_;
map { [ $state_name, $_ ] } # value => [ $state_name, $value ]
values(%{ $VAR1->{$_} ) # Get the state's property values.
}
values(%$VAR1); # Get the countries.这些是不可读的。最好避免这样做。
最后,如果要执行许多基于ISO2的搜索,最好是按照ISO2组织数据。
my %by_iso2 = (
'ISO2:4166-23:US' => {
country_name => 'USA',
state_name => 'Alabama',
ISO2 => 'ISO2:4166-23:US',
ISO3 => 'ISO3:3166-2:US',
...
},
'ISO2:4166-23:US' => {
country_name => 'USA',
state_name => 'Washington',
ISO2 => 'ISO2:30-23:US',
ISO3 => 'ISO3:40-166-2:US',
...
},
...
);发布于 2020-10-07 15:25:31
不是的。散列是单向的,所以您必须遍历所有的值才能找到正在搜索的值。
听起来你真正想要的是某种数据库,而哈希是你工作的错误工具。
您可以相反地构建您的散列,使用ISO2作为键。
$VAR1 = {
"ISO2:4166-23:US" => { Country => 'USA', State => 'Alabama' },
"ISO2:4166-23:US" => { Country => 'USA', State => 'Washington' }
}如果您打算做很多这些查找,这可能是值得的。这样做也可以是自动化的。使用类似的循环来构建一个新的哈希作为查找。
就速度而言,遍历所有哈希键没有什么问题。直接查找和循环之间的差别是可以忽略不计的,除非你有一个真正巨大的哈希。
https://stackoverflow.com/questions/64246116
复制相似问题