如何破译哈希数组?

How do I decipher an array of hashes?

这道题我完全答错了。我正在使用 TMDB 中的方法:

 my @results = $search->find(id     => 'tt0114694', source => 'imdb_id');

我以为输出是 JSON 格式,这让我很困惑,这让我 运行 原地转了一圈,因为我完全看错了。

没有意识到下面来自 Dumper 的数据是我必须经过的实际哈希值。

这是我运行撞墙的地方,所以下面的数据是一个有五个键的散列。第五个键 I want 包含另一个数组。这是我无法读入的数组。我尝试将其取消引用为散列,这就是我失败的地方。

我正在尝试的代码是:

foreach my $narray (@results){
    print $narray->{"movie_results"};
    my @newarray = $narray->{"movie_results"};

    foreach my $otherarray (@newarray){
        my %innerhash = $otherarray;
        print %innerhash;
        print "\n";
    }
  } 

它将打印出一个数组,但我无法读取该数组中的散列。

p.s。我必须将此输出格式化为代码,否则输出时没有换行符。

   $VAR1 = {
              'tv_season_results' => [],
              'tv_results' => [],
              'person_results' => [],
              'tv_episode_results' => [],
              'movie_results' => [
                                   {
                                     'adult' => bless( do{\(my $o = 0)}, 'JSON::PP::Boolean' ),
                                     'vote_average' => '6.8',
                                     'original_title' => 'Tommy Boy',
                                     'vote_count' => 635,
                                     'id' => 11381,
                                     'release_date' => '1995-03-31',
                                     'overview' => 'Party animal Tommy Callahan is a few cans short of a six-pack. But when the family business starts tanking, it\'s up to Tommy and number-cruncher Richard Hayden to save the day.',
                                     'genre_ids' => [
                                                      35
                                                    ],
                                     'title' => 'Tommy Boy',
                                     'video' => $VAR1->{'movie_results'}[0]{'adult'},
                                     'poster_path' => '/g32WbO9nbY5ydpux5hIoiJkLEQi.jpg',
                                     'original_language' => 'en',
                                     'backdrop_path' => '/bZ4diYf7oyDVaRYeWG42Oify2mB.jpg',
                                     'popularity' => '13.945'
                                   }
                                 ]
            };

%newhash{$newkey} 应该是 $newhash{$newkey}.

处理引用时,使用与未处理引用相同的语法,但将变量名称替换为 returns 引用的块。

%NAME      -> %{ $ref }           Or just %$ref
$NAME{...} -> ${ $ref }{...}      Although $ref->{...} easier to read.

@NAME      -> @{ $ref }           Or just @$ref
$NAME[...] -> ${ $ref }[...]      Although $ref->[...] easier to read.

让我们给$VAR一个更好的名字,

my $response = $VAR1;

这意味着你想要

my $results = $response->{movie_results};
for my $result (@$results) {
   for my $key (keys(%$result)) {
      say "$key: $result->{$key}";
   }
}

你提到你认为你会得到 JSON 输出,但得到了其他东西。该模块为您发出 Web 请求,收到 JSON 响应,并将其转换为 Perl 数据结构。 JSON 的 Perl 版本就是您在转储中看到的。

一个 JSON 对象变成一个 Perl 散列,所以这就是您在数据结构的顶层看到的。这是一件事情 find returns(稍后会详细介绍):

这是您所拥有的,删除了外部 foreach 循环:

my @newarray = $narray->{"movie_results"};

foreach my $otherarray (@newarray){
    my %innerhash = $otherarray;
    print %innerhash;
    print "\n";
}

$narray->{"movie_results"} 中的值是一个数组引用。所有引用都是标量,这些标量指向某个数据结构。当您将该标量分配给一个数组时,您最终会得到一个具有相同引用的单元素数组。相反,您可以

my $movie_results = $narray->{"movie_results"};

然后取消引用该引用以将其视为数组:

foreach my $result ( @$movie_results ){ ... }

或者,我觉得 v5.24 postfix dereferencing 方式稍微更令人愉悦,因为它读起来更好,尤其是当您跳过中间变量时:

foreach my $result ( $movie_results->@* ){ ... }

foreach my $result ( $narray->{"movie_results"}->@* ){ ... }

$result 中的那个东西是另一个哈希引用。

引用和数据结构大约是Intermediate Perl, but there is also the Perl data structures cookbook (perldsc)的一半内容。

稍微改进一下你的问题

您可以通过向我们展示您的问题的完整、有效的演示来帮助我们很多。这是我拼凑的:

use v5.10;

use TMDB;
use Data::Dumper;

my $tmdb = TMDB->new( apikey => $ENV{TMDB_API_KEY} );
my @results = $tmdb->search->find(
    id     => 'tt0114694',
    source => 'imdb_id'
    );

say Dumper( \@results );

find 的结果存在问题。文档示例显示它 returning 一个列表(好吧,结果被分配给一个命名数组,这意味着),但是 find 没有实际的文档。它 return 是来自响应的解码 JSON。将它分配给一个标量(这将是一个参考)也可以正常工作:

my $result = $tmdb->search->find(
    id     => 'tt0114694',
    source => 'imdb_id'
    );

say Dumper( $results );

return 值来自 TMDB::Sesssion::talk(),也就是这个(或空列表):

return $self->json->decode(
    Encode::decode( 'utf-8-strict', $response->{content} ) ); 

这没什么大不了的。这只是意味着您不需要外部 foreach。这不是你的责任,因为文档中的示例告诉你完全按照你所做的去做。

现在更好的程序

将所有这些放在一起,这里有一个简单的程序,可以满足您的需要:

use v5.10; 
use TMDB;

my $tmdb = TMDB->new( apikey => $ENV{TMDB_API_KEY} );
my $result = $tmdb->search->find(
    id     => 'tt0114694',
    source => 'imdb_id'
    );

foreach my $item ( $result->{movie_results}->@* ) {
    say "Title: $item->{title}";
    }

引用别名

有一项名为 ref aliasing 的实验性功能,可让您将引用分配给命名变量的引用。它是一个别名,因此您可以访问和更改相同的数据,只需使用命名变量即可。当你不喜欢的时候这很方便

use v5.10;

use TMDB;
use experimental qw(refaliasing);

my $tmdb = TMDB->new( apikey => $ENV{TMDB_API_KEY} );

# response is a hash ref, so ref alias to a named hash
\my %result = $tmdb->search->find(
    id     => 'tt0114694',
    source => 'imdb_id'
    );

# the part you want is an array ref, so alias that
\my @movie_results = $result{movie_results};

# each item in the array is a hash ref, so alias those too
foreach \my %item ( @movie_results ) {
    say "Title: $item{title}";
    }