6

私は次のようにデコードしているjson構造を持っています:

  person => {
    city => "Chicago",
    id => 123,
    name => "Joe Smith",
    pets => {
      cats => [
                { age => 6, name => "cat1", type => "siamese", weight => "10 kilos" },
                { age => 10, name => "cat2", type => "siamese", weight => "13 kilos" },
              ],
      dogs => [
                { age => 7, name => "dog1", type => "siamese", weight => "20 kilos" },
                { age => 5, name => "dog2", type => "siamese", weight => "15 kilos" },
              ],
    },
  },
}

次のようにしてcity、、を印刷できます。idname

foreach my $listing ($decoded->{person})
{ 
    my $city = $listing->{city};
    my $name = $listing->{name};
    name - $city - \n";
}

pets->catsただし、またはを印刷する方法がわかりませんpets->dogs。私はそれらのダンプを行うことができます:

my @pets = $listing->{pets}->{cats};
dump @pets;

しかし、ハッシュ構造を介してそれらにアクセスする方法がわかりません。

4

3 に答える 3

9

$listingあなたがであると仮定すると、配列とハッシュ参照を逆参照する必要があります。

# as long as we are assuming $listing is a person
# this goes inside the foreach you posted in your
# question.

# this will print all cats' names
foreach my $cat ( @{ $listing->{pets}->{cats} } )
{
    # here $cat is a hash reference

    say $cat->{name}; # cat's name
}

他のものについても同様です。

構造からそれらにアクセスするには、次のことができます。

say $listing->{pets}->{cats}->[0]->{name}; # this will print 'cat1'
于 2011-11-24T14:18:14.637 に答える
9

ルールを理解すれば、大きな構造を掘り下げるのは非常に簡単です。

  • ハッシュキーをラップする{}
  • 配列インデックスをラップする[]
  • トップレベルの変数が参照である場合は->、最初の識別子の前に使用します。
  • 中括弧または角かっこの最初のセットの後、追加の矢印(->)はオプションです。

したがって、*は*を$data->{person}{name}返します'Joe Smith' *$data->{person}->{name}も返します'Joe Smith' *はを$data->{pets}{cats}[0]{age}返します6

このトピックの詳細については、Perlデータ構造クックブック(perldoc perldsc)を参照してください。

このような大きな構造物を扱う場合、注意すべき重要なことがいくつかあります。これらの最大のものはautovivificationです。Autovivは、Perlがデータ構造要素を自動的に作成して、作業を楽にすることを意味します。残念ながら、それは物事を困難にする可能性もあります。

たとえば、私がこれを行うとき、autovivは素晴らしいです:

my $data;
$data->{horse}[0]{color} = 'brown';

Autovivは魔法のように、値として配列refを持つ$dataキーを含むhashrefに変わります。horse配列refには、ハッシュrefが入力されます。最後のハッシュ参照は、キーと値のペアを取得しますcolor => brown

問題は、構造物を歩いているときに、存在について詳細なテストを行うときに発生します。

# Code from above continues:

if( exists $data->{cat}[5]{color} ) {
    print "Cat 5 has a color\n";
}

use Data::Dumper;
print Dumper $data;

ここで、自動生存はデータに大量のジャンクを作成することによってあなたを燃やします、これがプログラム出力です:

$VAR1 = {
      'cat' => [
                 undef,
                 undef,
                 undef,
                 undef,
                 undef,
                 {}
               ],
      'horse' => [
                   {
                     'color' => 'brown'
                   }
                 ]
    };

これで、構造の各層の存在を注意深くテストすることで、この種の問題を防ぐことができますが、それはお尻の大きな痛みです。代わりに、Data::Diverを使用することを好みます。

use Data::Diver qw( Dive );

my $dog_20_color = Dive( $data, 'dog', 20, 'color' );
print "Dog 20 is $dog_20_color\n" if defined $dog_20_color;

$dataここでは変更されていません。

Diveまた、キーまたはインデックスのリストを取得するため、プログラムでキー/インデックスのリストを作成し、コード内の任意のパスを下るのが簡単であることに気付いたかもしれません。

Data :: Diverは、大きくて不安定なデータ構造を大量に操作する必要がある場合に、実際の節約になります。

于 2011-11-24T16:59:00.277 に答える
2
my @pets = $listing->{pets}->{cats};

これはあなたが思っていることをしていません。配列への参照$listing->{pets}->{cats}が含まれています。新しい配列には、最終的に1つの要素(配列参照)のみが含まれます。@pets

実際に必要なのは

my @pets = @{ $listing->{pets}{cats} };

これにより、配列参照が異なり、実際の配列が取得されます。式にオプションの2番目の矢印もドロップしたことに注意してください。

配列を取得すると、その各要素がハッシュ参照になります。

foreach (@pets) {
  say $_->{name};
  # etc ...
}

もちろん、中間配列はまったく必要ありません。

foreach (@{ $listing->{pets}{cats} }) {
  say $_->{name};
}
于 2011-11-24T14:54:20.847 に答える