Complex Data Structures

We now want to use references to build some higher level data structures.

Two-Dimensional Arrays

Suppose you want to build an array with two dimensions. Conceptually, you might think of this as rows and columns, but Perl thinks of this as an array of arrays. A first attempt may result in something like

@a1 = (10,20,30);
@a2 = (100,200,300);
@matrix = (@a1, @a2);

but this simply creates one flat array with six elements.

print "@matrix"; # prints 10,20,30,100,200,300

Instead, you could populate an array with references to anonymous arrays. See the folder TwoDim.


% type twodim.pl
#
#   twodim.pl
#
@twodim = (        [10, 20, 30],
                   [40, 50, 60],
                   [70, 80, 90]
          );
print "@twodim
";
print "$twodim[0]
";
print "$twodim[1]
";
print "$twodim[2]
";
%

Each item of the form

[10, 20, 30]

is a reference, and thus @twodim is an array of references to anonymous arrays. If you execute the program above, you will see the following output.

% perl twodim.pl
ARRAY(0x176f09c) ARRAY(0x17650f4) ARRAY(0x176516c)
ARRAY(0x176f09c)
ARRAY(0x17650f4)
ARRAY(0x176516c)
%

The first print above prints all the elements of the array, which of course are simply references to anonymous arrays. From this, it follows that the last three prints print single references. To get at the actual data in these anonymous arrays, you must dereference each anonymous array.

How you actually perform the dereferencing depends upon which chunk of data you wish to access. If you want to print each row, you can simply dereference each anonymous array reference.

foreach $row (@twodim)
{
     print "@$row
";
}

Perl also allows some shortcuts here. The simplest way to get at a particular element is to use two subscripts.

print $twodim[0][0]         # prints the 10
print $twodim[0][1]         # prints the 20
print $twodim[1][0]         # prints the 40

Two-dimensional arrays may also be built on the fly. For example, if the first access to an array in your program is

$data[5][6] = 0;

then you have created an array of 42 elements (not 30, because array subscripts start at 0, not 1).

Finally, you may have a jagged array, one in which there are a different number of elements in each row. See the folder Disparate.


% type disparate.pl
#
#   disparate.pl
#
@values = (  [1, 2, 3, 4, 5 ],
             [Mike, Judy, Joel],
             [Prov, Boston]
          );
for ( $i = 0; $i < @values; $i++)
{
    for ($j = 0; $j < @{$values[$i]}; $j++)
    {
          print $values[$i][$j], " ";
    }
    print "
";
}
% perl disparate.pl
1 2 3 4 5
Mike Judy Joel
Prov Boston
%

The outer loop performs three iterations, one for each reference in the array. In a scalar context, @values yields 3, the number of elements in the @values array. Since the array is not rectangular, the number of inner loop iterations depends upon how many elements are contained within each referenced array.

The following expression used in a scalar context yields the correct number of elements in each row.

@{$values[$i]}

There is yet another approach we can take. We can have a reference to a bunch of references. If you are a C programmer, you may know this idiom as a pointer to a bunch of pointers—similar to argv.

$t =    [    [1, 2, 3, 4, 5 ],
             [Mike, Judy, Joel],
             [Prov, Boston]
        ];

$t is a reference to three anonymous references. To get at any of the elements, there needs to be an additional indirection with respect to previous array examples.

print "$t 
";                  # ARRAY ref
print "$$t[0]
";               # ARRAY ref
print "$$t[1]
";               # ARRAY ref
print "$$t[0][0]
";            # 1
print "$$t[1][0]
";            # Mike
print "@{$$t[2]}
";            # Prov Boston

Complex Hashes

All of the hashes thus far have consisted of pairs, where each pair consisted of a key and a simple value. The value can be arbitrarily complex—it could be a scalar, an array, another hash, a subroutine, or any other complex data that you need. For example, in the following hash, each name is mapped to an anonymous array.

%courses = (    Mike  =>       [CPP, Java, Perl],
                Patti =>       [HTML, C],
                Dave  =>       [JSP, XML]
           );

If we wanted to display the courses that Mike teaches, we could simply dereference the expression $courses{Mike}. The code would be

print @{$courses{Mike}};

If we wanted a particular course, we could just supply the appropriate subscript on the previous expression. For example, the following expression would display Java.

print @{$courses{Mike}}[1];

Thus, we could use the following to print all of the courses.

foreach $key (keys(%courses))
{
    print @{$courses{$key}}, "
";
}

Each $courses{$key} reference above returns a reference to an array, which then must be dereferenced with @. If we wanted to build an array of all of the courses, we could code

foreach $key (keys(%courses))
{
    foreach $course (@{$courses{$key}})
    {
          push(@courses, $course);
    }
}

Rather than having an actual hash, we could have a reference to one. This would change the notation a bit.

$fac = {    Mike  =>    [CPP, Java, Perl],
            Patti =>    [HTML, C],
            Dave  =>    [JSP, XML]
       };
print @{$$fac{Mike}}, "
";
foreach $key (keys(%$fac))
{
    print @{$$fac{$key}}, "
";
}

Note that a reference to an anonymous array uses the [ ] notation

$anonarray = [ 10, 20, 30 ];

whereas a reference to an anonymous hash uses the { } notation.

$hash = {  a => b, c=> d };

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.216.249