首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用于嵌套哈希而不是使用循环的Perl grep命令

用于嵌套哈希而不是使用循环的Perl grep命令
EN

Stack Overflow用户
提问于 2020-10-07 14:22:24
回答 2查看 98关注 0票数 1

我有下面的散列结构。

代码语言:javascript
复制
$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名称。我想做的是:

我可以通过下面的代码获得所需的输出。

代码语言:javascript
复制
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命令?

任何指向正确方向的指针都是有用的。谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-10-07 21:35:01

你的变量名字很差。重用$states作为州名吗?唉哟。

代码语言:javascript
复制
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)。

代码语言:javascript
复制
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

代码语言:javascript
复制
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值,这将简化为以下内容:

代码语言:javascript
复制
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一个州名列表。

代码语言:javascript
复制
my @state_names = ...;

my ($found_state_name) =
   grep { ... }
      @state_names;

我们可以使用以下方法获得状态名称列表

代码语言:javascript
复制
my @state_names =
   map { keys(%$_) }
      values(%$VAR1);

但这还不足以进行检查。(现在,我将假设只需要检查ISO2属性。)

代码语言:javascript
复制
my @state_names =
   map { keys(%$_) }
      values(%$VAR1);

my ($found_state_name) =
   grep { $VAR1->{???}{$_}{ISO2} eq $find }
      @state_names;

有两种解决办法。你可以和乡村州对一起工作。

代码语言:javascript
复制
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;

或者,您可以创建一个简单的状态列表并搜索它。

代码语言:javascript
复制
my @states_with_name = 
   map { [ $_, $VAR1->{$_} ] }
      values(%$VAR1);

my ($found_state_name) =
   map { $_->[0] }
      grep { $_->[1]{ISO2} eq $find }
         @states_with_name;

注意阻止我们合并这两个语句。

代码语言:javascript
复制
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)。(我将只对上述两种解决方案中的后一种进行修改。)

代码语言:javascript
复制
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.

代码语言:javascript
复制
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组织数据。

代码语言:javascript
复制
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',
      ...
   },
   ...
);
票数 1
EN

Stack Overflow用户

发布于 2020-10-07 15:25:31

不是的。散列是单向的,所以您必须遍历所有的值才能找到正在搜索的值。

听起来你真正想要的是某种数据库,而哈希是你工作的错误工具。

您可以相反地构建您的散列,使用ISO2作为键。

代码语言:javascript
复制
$VAR1 = { 
    "ISO2:4166-23:US" => { Country => 'USA', State => 'Alabama' },
    "ISO2:4166-23:US" => { Country => 'USA', State => 'Washington' }
}

如果您打算做很多这些查找,这可能是值得的。这样做也可以是自动化的。使用类似的循环来构建一个新的哈希作为查找。

就速度而言,遍历所有哈希键没有什么问题。直接查找和循环之间的差别是可以忽略不计的,除非你有一个真正巨大的哈希。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/64246116

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档