Home > Net >  Nested perl arrays and hashes and references
Nested perl arrays and hashes and references

Time:09-17

I have tried various combinations of @%$s but I cannot get this to work. The full expression works, but how do I split it up into variables?

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", %col, " ", "\n"; #prints 1 ?
print "COLexp ", $cols[1]{_name}, "\n";  ######## Fails, uninitialized.

I want to represent database schemas. So a map of tables, each containing an array of columns, each of which is a map. Here is the full fragment.

my %tables=();

my $columns; # array

sub addTable {
  my @cols = ();
  $tables{$_[0]} = \@cols;
  $columns = \@cols;
}

sub addColumn {
    my %col  = (_name => $_[0],  _typ => $_[1]);
    push(@$columns , \%col);
}

addTable("grp");
addColumn("id", "serial");
addColumn("part", "integer");

addTable("tab2");
addColumn("foo2", "varchar");
addColumn("bar2", "integer");

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", %col, " ", "\n"; #prints 1 ?
print "COLexp ", $cols[1]{_name}, "\n";  ######## Fails, uninitialized.

I am new to Perl and have yet to become "Perl minded" :(. Any help much appreciated.

CodePudding user response:

You can use the module use Data::Dumper; in order to print your data structures.

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, prints part
my @cols = $tables{"grp"};
print "COLS ", @cols, "\n"; # prints array
my %col = %cols[1]; 
print "COLvar ", Dumper(\%col), " ", "\n"; #prints 1 ?
print "COLexp ", Dumper(\@cols), "\n";  ######## Fails, uninitialized.

print "COLexp ", Dumper($cols[0][1]{_name}), "\n";

And the output is like:

   BIGexp part
COLS ARRAY(0x800e5f480)
COLvar $VAR1 = {
          '1' => undef
        };
 
COLexp $VAR1 = [
          [
            {
              '_typ' => 'serial',
              '_name' => 'id'
            },
            {
              '_name' => 'part',
              '_typ' => 'integer'
            }
          ]
        ];

COLexp $VAR1 = 'part';

As you can see, you actually have a nested array. So you need to access the nested array first and then the hash.

CodePudding user response:

Following sample demo code provides one of many possible ways to form what OP named as database shema.

OP in function addColumn($name, $type) does not specifies what table the column belong to.

It would be nice to see what final data structure OP expects to build to clarify what would be final result.

The sample code provided in a hope that it might assist OP in finding solution to his/her problem.

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

use Data::Dumper;

my %tables;

tbAddColumn('grp','id','serial');
tbAddColumn('grp','part','integer');

tbAddColumn('tab2','foo2','varchar');
tbAddColumn('tab2','bar2','integer');

say Dumper(\%tables);

my $tb_name = 'grp';

say "Table: $tb_name";
say '-' x 45;

for my $column ( @{$tables{$tb_name}{columns}} ) {
    say "name => $column->{name}, type => $column->{type}";
}

exit 0;

sub tbAddColumn {
    my $tbname = shift;
    my $name   = shift;
    my $type   = shift;

    push @{$tables{$tbname}{columns}}, { name => $name, type => $type};
}

Output

$VAR1 = {
          'tab2' => {
                      'columns' => [
                                     {
                                       'name' => 'foo2',
                                       'type' => 'varchar'
                                     },
                                     {
                                       'name' => 'bar2',
                                       'type' => 'integer'
                                     }
                                   ]
                    },
          'grp' => {
                     'columns' => [
                                    {
                                      'name' => 'id',
                                      'type' => 'serial'
                                    },
                                    {
                                      'type' => 'integer',
                                      'name' => 'part'
                                    }
                                  ]
                   }
        };

Table: grp
---------------------------------------------
name => id, type => serial
name => part, type => integer

NOTE: OP could do some reading on object oriented programming in Perl which would allow incapsulate table data/structure into an object. Result code would look much cleaner and easier to maintain.

Sample of pseudo code

......
my $tb1 = new dbTable('grp');
my $tb2 = new dbTable('tab2');

$tb1->addColumn('id','serial');
$tb1->addColumn('part','integer');


$tb2->addColumn('foo2','varchar');
$tb2->addColumn('bar2','integer');
.....

CodePudding user response:

The syntax %cols[1] is an index-value array slice. If @cols only has a single element, the value at index 1 is undefined and %cols[1] returns the list (1, undef) which is assigned to %col at line 4 in your first snippet:

my %col = %cols[1];

So now %col = ("1" => undef) and when you try to print it on line 5:

print "COLvar ", %col, " ", "\n";

It tries to print the key "1" joined with the value undef which gives a warning and then the output:

Use of uninitialized value in print
COLvar 1

CodePudding user response:

Thanks for the posts, but none of them solved the actual problem. The solution is

print "BIGexp ", $tables{"grp"}[1]{_name}, "\n"; # OK, part
my $cols = $tables{"grp"};  # ref array
my $col = ${$cols}[1];  # ref hash
my %colh = %{$col}; # hash
print "COLvar ", $colh{_name}, " ", "\n"; # bingo
print "COLvar2 ", ${$col}{_name}, " ", "\n"; # bingo
print "COL-> ", $col->{_name}, " ", "\n"; # bingo

The trick is taking care of the difference between a ref array and an array etc. {$x} is the dereference operator.

I still do not really understand what "%" etc. really does though. I suspect it is best to only ever use references and avoid % and @ entirely.

This link was very helpful https://perldoc.perl.org/perlreftut

  •  Tags:  
  • perl
  • Related