lulutreizequinze
lulutreizequinze

Reputation: 3

perl+json getting size of an array

I'm reading a json file in perl and having trouble using the results.

I want to know how many views are present in the json file. there should be 2

my $data = decode_json($json);
print Dumper($data);

my @tmp=$data->{'views'};
my $nviews=scalar @tmp;
print "nviews : $nviews\n";

gives me

$VAR1 = {
    'views' => [
        {
            'key' => 0,
            'value' => {
                'ptr_wrapper' => {
                     'data' => {
                         'width'    => 776,
                         'height'   => 1024,
                         'id_view'  => 0,
                         'filename' => '000118800_15821618907.jpg',
                         'id_pose'  => 0,
                         'id_intrinsic' => 13,
                         'local_path' => '/'
                     },
                     'id' => 2147483649
                 }
             }
        },
        {
             'key'   => 1,
             'value' => {
                 'ptr_wrapper' => {
                      'data' => {
                          'id_pose'      => 1,
                          'id_intrinsic' => 11,
                          'filename'     =>  '000132800_22050281512.jpg',
                          'id_view'      => 1,
                          'local_path'   => '/',
                          'width'        => 850,
                          'height'       => 1024
                      },
                      'id' => 2147483650
                  }
             }
         }
    ]
};
nviews : 1

thanks in advance for any help.luc

Upvotes: 0

Views: 3045

Answers (2)

Borodin
Borodin

Reputation: 126722

When you write this

my $data = decode_json($json);

my @tmp = $data->{'views'};

you are creating a Perl array with a single element $tmp[0] that is identical to $data->{'views'}.

Your $data->{'views'} is spot on, so you have correctly understood how to access the views element of the hash referred to by your $data variable, and as long as the hash key views looks like a Perl identifier you can forget the quotes around it

But the values of Perl hashes and arrays are always scalar, so you must dereference them if you need to access the array, and the same applies to any substructures that you need to access

If you are dealing with complex data structures, it is usually best to keep a temporary scalar variable that tracks where you are within the structure. For instance, I would write

my $views = $data->{views};

Now I have a simple array reference to code with. I can dereference it to an array with @$views, and I can access its elements with $views->[0] etc.

Here's a rewrite of your own code that does what I have described. I have also used Data::Dump to reformat the data that you show. It is generally far more concise and readable than the output from Data::Dumper, but it isn't a core module so you will probably have to install it

I pull out $value->{ptr_wrapper} as a lexical variable $wrapper, and in turn $wrapper->{data} as lexical variable $data. The rest of the code becomes so much simpler, as I could otherwise be writing stuff like

say $data->{views}[0]{value}{ptr_wrapper}{data}{filename}


use strict;
use warnings 'all';
use feature 'say';

my $data = {
  views => [
    {
      key => 0,
      value => {
        ptr_wrapper => {
          data => {
            filename     => "000118800_15821618907.jpg",
            height       => 1024,
            id_intrinsic => 13,
            id_pose      => 0,
            id_view      => 0,
            local_path   => "/",
            width        => 776,
          },
          id => 2147483649,
        },
      },
    },
    {
      key => 1,
      value => {
        ptr_wrapper => {
          data => {
            filename     => "000132800_22050281512.jpg",
            height       => 1024,
            id_intrinsic => 11,
            id_pose      => 1,
            id_view      => 1,
            local_path   => "/",
            width        => 850,
          },
          id => 2147483650,
        },
      },
    },
  ],
};

my $views = $data->{views};
my $nviews = scalar @$views;

print "nviews : $nviews\n\n";

for my $view ( @$views ) {

    my $key     = $view->{key};
    my $value   = $view->{value};
    my $wrapper = $value->{ptr_wrapper};
    my $data    = $wrapper->{data};

    say "key      = $key";
    say "ID       = $wrapper->{id}";
    say "filename = $data->{filename}";
    say "height   = $data->{height}";
    say "width    = $data->{width}";
    print "\n";
}

output

nviews : 2

key      = 0
ID       = 2147483649
filename = 000118800_15821618907.jpg
height   = 1024
width    = 776

key      = 1
ID       = 2147483650
filename = 000132800_22050281512.jpg
height   = 1024
width    = 850

Upvotes: 4

jcaron
jcaron

Reputation: 17710

my $views = $data->{views};
my $nbViews = scalar @$views;

$data->{views} is a reference to an array, not an array. Store the reference, and dereference it when needed.

Alternatively:

my @views = @{$data->{views}};
my $nbViews = scalar @views;

As pointed out by Borodin, note that this alternative makes a copy of the original array (potentially using a lot of memory). In some cases that may be what you actually want to do (if you need to modify it while leaving the original one intact, though note this would not be a deep copy), but most often (especially if you just want to count the items or iterate over them), you probably don't want to do that and just stick to keeping a reference (as in the first code snippet above).

Upvotes: 5

Related Questions