Building Data Structures with Existing Data

The examples of creating nested data structures with anonymous data work great when you already know exactly what data that structure is going to contain ahead of time. But in real life, these sorts of structures tend to get built from data that might be read in from a file or entered via the keyboard.

In that case, sometimes you'll end up combining anonymous data with references to regular variables. As long as you end up with references in the right spot, there's no harm in using whatever mechanism works best for building your data structure. For example, let's say that you had a file that contained a matrix of numbers that looked something like this:

3 4 2 4 2 3
5 3 2 4 5 4
7 6 3 2 8 3
3 4 7 8 3 4

You want to read that file into an array of arrays, with each row its own array, and a larger array to store the individual rows. You might accomplish that with a loop that looks something like this:

while (<>) {
   chomp;
   push @matrix, [ split ];
}

That loop would read each line, chomp off its newline with chomp, split it into elements with split, create an anonymous array of those elements with brackets, and then finally push the reference to that array onto a larger array.

You might think that this example would be more readable if we split the elements into a list first, and then stored a reference to that list instead, like this:

my @list = ();
while (<>) {
   chomp;
   @list = split;
   push @matrix, @list;
}

But there's a big catch to this example (a catch lots of programmers make the first time they try this). Given input like the preceding matrix, with this loop you'd end up with an array of arrays that looked like this:

3 4 7 8 3 4
3 4 7 8 3 4
3 4 7 8 3 4
3 4 7 8 3 4

Can you guess why? The problem is with the variable name and, later, the reference to it. With each turn of the loop, although the contents of the variable @list change, the memory location stays the same. Each time you read a line, you're pushing a reference to the same memory location. The array you end up with is an array of four references, and each one points to exactly the same place.

One solution to this mistake—and it's a common one, so watch out for it—is to create a reference to a copy of the array's data, not to the array itself. This way, a new location is created in memory each time the loop executes, so you end up with references to different places. You can do this simply by putting anonymous array brackets around your array variable:

my @list = ();
while (<>) {
   chomp;
   @list = split;
   push @matrix, [ @list ];
}

Watch out with hashes that you do the same thing with an anonymous hash (in this case, putting an anonymous hash into an array of hashes):

push @arrayofhashes, { %hash } ;

The other solution to this problem is to use a my variable inside the loop itself. Because the my variable will be created from scratch at each turn of the loop, the references will point to different bits of memory each time:

while (<>) {
   chomp;
   my @list = split;
   push @matrix, @list ;
}
					

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

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