At first: Apologies for my not-so-good English, I'm a 17-year old German ;-)
I do my apprentice as a web-developer and just stumbled upon a problem:
I need to re-arrange the indexes of an array. The array is basically like that:
#array = ( 'a', 'b', 'c' );
But: it changes dynamically, so it doesnt always have 3 elements, but something over 20. Now, what I need to do is to get it to:
#array = ( 'c', 'a', 'b' );
So, I thought I just needed to do something like that (in a for-loop that loops once for every element in the array and increments $counter)
my $last = $array[$#array];
for($#array)
{
$array[$counter] = $array[$counter + 1];
unshift(#array, $last);
pop(#array);
$counter++;
}
I thought it would do this:
For each element in array (lets say, we are at element 0): Set element index = element index + 1; then add the last array to the beginning and remove the now "real" last array (which is just a duplicate of the beginning now). Then adding 1 to the counter and redo that for the array. But it doesnt really do what I want.
Well, that was my "newbie" try, so again, thats what I just need:
I need to "move" all the elements indexes of the array +1 and cut off the last one then to be at the beginning. The maybe more complicated thing is, that the arrays length is just variable.
In another form:
I need to turn
( 'a', 'b', 'c', 'd', ... 'z');
to
( 'z', 'a', 'b', 'c', ... 'y' );
Ive got no idea how to go on and I would appreciate any help.
Thanks :-)
Already thanks for all your anwers! I forgot to say that I cant test it before monday, because Im not at work anymore and I dont have the source with me right now. But thanks, Im sure at least one of your solutions will work!
#array = { 'c', 'a', 'b' };
assigns a single element (a hash reference) to #array; I think you mean
#array = ( 'c', 'a', 'b' );
This for loop:
for ($#array)
only loops over the single value $#array (the last index of #array).
I'm guessing you meant something like:
for ( 0..$#array )
(loop over all the array indicies).
Inside your loop, you seem to be doing two different things; one rotating things with unshift/pop and one moving things with an assignment of elements. Either approach would work (though in both you have errors), but both will not.
You can do:
my $last = $array[$#array];
for ( 0..$#array-1 ) {
$array[$_+1] = $array[$_];
}
$array[0] = $last;
(no separate counter needed; the loop provides one)
or rotate by one (moving the first element to be last) the array one fewer times than there are elements:
for ( 1..$#array ) {
push #array, shift #array;
}
or just do this to take the last element and make it first:
unshift #array, pop #array;
Or you can reassign all the elements at once, using a slice:
#array = #array[ $#array, 0..$#array-1 ];
or
#array[1..$#array, 0] = #array;
All of these produce the change you seem to want, but I don't feel confident you've explained clearly enough what that change is, given how complicated your attempt is compared to what would be needed to do what your example shows.
First, use round brackets for creating arrays in Perl:
#array = ('a', 'b', 'c');
If you want to move the last element to the beginning of the array, you can use:
unshift #array, pop #array;
I think you might want to take a look at List::Util, it's got a shuffle method that literally shuffles list contents.
Related
I want to count how much D and E and F contains the array ary in total.
I can do it like
ary.count('D') + ary.count('E') + ary.count('F')
or like
count = 0
'DEF'.split('').each do |letter|
count += ary.count(letter)
end
count
but both of it don't look very smart to me, is there a better way in ruby? Unfortunately, .count('D','E','F') does not work.
You could use a regex.
ary.grep(/\A(D|E|F)\z/).size
You can easily build this regex from array ['D', 'E', 'F'], but I'll leave that up to you.
It's pretty straightforward if you're simply counting letters:
letters = 'AEIOU'.chars
matches = 'FISSION'.chars.grep(Regexp.union(letters)).count
Where this is useful for matching single letter instances in a case-sensitive manner. Here Regexp.union creates a single regular expression that matches any of those letters.
You can pass a block to Array#count, as follows:
ary.count { |item| %w(D E F).include?(item) }
This will return a count of how many elements for which the block returns a truthy (not nil or false) value.
%w() is a nice syntax for defining an array of strings - i.e. the following are equivalent:
['D', 'E', 'F'] == %w(D E F)
You were close. It's actually very simple, using a little-known feature of String#count:
'DEF'.count('DEF') #=> 3
'FEED ME'.count('DEF') #=> 5
How would I modify (add/remove elements) an array while iterating over it and have the iterator be aware of it?
For example I would think this code:
a = "1234567890".split("")
a.each_with_index{|d, i|
if d.eql?('5')
a.delete_at(i)
a.insert(i, ['A', 'B', 'C'] )
end
print d
}
would produce: 1234ABC67890 but instead produces 1234567890
Is there a workaround or different method to make this work?
(I know this example is pretty simple example but I am doing some complicated text processing where I need to insert some text when I hit a key word. I do a bunch of functions before and after I would do the expansion so doing the insert outside of the each loop [aka map!] would really complicate my code)
Actually, your code works, you just need to replace print d with print a[i] since what you're printing is the variable d not the actual array element at index i
Rather than deleting and inserting, why not change the element on that index?
a = "1234567890".split("")
a.each_with_index{|d, i|
if d.eql?('5')
a[i] = ['A','B','C']
end
print a[i] #a[i] rather than d, since d contains the old value
}
or
...
if d.eql?('5')
a[i] = ['A','B','C']
d = a[i]
end
print d
Deleting/Inserting on an Array during iterations is discourage since it may cause headaches haha... Resort to other methods if possible :)
Note:
I've just used the current logic in your code based on my understanding, and the given desired output
the array will become [1,2,3,4,['A','B','C'],6,7,8,9,0] and not [1,2,3,4,'A','B','C',6,7,8,9,0]. If you want the other, just leave a comment :)
If what you want is just to change a value in the string, you can just use .tr or .gsub to do the job
Here is one option. If you want to return array then remove join otherwise keep it to return a String
a = "1234567890".split("")
a.collect! {|i| i == '5' ? ['A', 'B', 'C'] : i }.flatten!.join #=> "1234ABC67890"
Inserting and deleting while iterating is best avoided. Some problems disappear however when iterating in reverse order:
a = "1234567890".split("")
a.reverse_each.with_index{|d, i|
if d.eql?('5')
a.delete_at(i)
a.insert(i, ['A', 'B', 'C'] )
end
}
puts a.join # => 12345ABC7890
You can't in general modify an Enumerable while iterating over its members. In most such cases, you need to construct a new Enumerable as you go.
b = []
a.each_with_index do |d, i|
if d.eql?('5')
b << 'A' << 'B' << 'C'
else
b << d
end
end
On this page, it shows how to initialize an array, and if you scroll down a bit, under the section called "The Lists" it "explains" what lists are and how they're different from arrays.
Except it uses an example that's just exactly the same as declaring an array, and doesn't explain it whatsoever.
What is the difference?
Take a look at perldoc -q "list and an array". The biggest difference is that an array is a variable, but all of Perl's data types (scalar, array and hash) can provide a list, which is simply an ordered set of scalars.
Consider this code
use strict;
use warnings;
my $scalar = 'text';
my #array = (1, 2, 3);
my %hash = (key1 => 'val1', key2 => 'val2');
test();
test($scalar);
test(#array);
test(%hash);
sub test { printf "( %s )\n", join ', ', #_ }
which outputs this
( )
( text )
( 1, 2, 3 )
( key2, val2, key1, val1 )
A Perl subroutine takes a list as its parameters. In the first case the list is empty; in the second it has a single element ( $scalar); in the third the list is the same size as #array and contains ( $array[0], $array[1], $array[2], ...), and in the last it is twice as bug as the number of elements in %hash, and contains ( 'key1', $hash{key1}, 'key2', $hash{key2}, ...).
Clearly that list can be provided in several ways, including a mix of scalar variables, scalar constants, and the result of subroutine calls, such as
test($scalar, $array[1], $hash{key2}, 99, {aa => 1, bb => 2}, \*STDOUT, test2())
and I hope it is clear that such a list is very different from an array.
Would it help to think of arrays as list variables? There is rarely a problem distinguishing between scalar literals and scalar variables. For instance:
my $str = 'string';
my $num = 99;
it is clear that 'string' and 99 are literals while $str and $num are variables. And the distinction is the same here:
my #numbers = (1, 2, 3, 4);
my #strings = qw/ aa bb cc dd /;
where (1, 2, 3, 4) and qw/ aa bb cc dd / are list literals, while #numbers and #strings are variables.
Actually, this question is quite well answered in Perl's FAQ. Lists are (one of) methods to organize the data in the Perl source code. Arrays are one type of storing data; hashes are another.
The difference is quite obvious here:
my #arr = (4, 3, 2, 1);
my $arr_count = #arr;
my $list_count = (4, 3, 2, 1);
print $arr_count, "\n"; # 4
print $list_count; # 1
At first sight, there are two identical lists here. Note, though, that only the one that is assigned to #arr variable is correctly counted by scalar assignment. The $list_count stores 1 - the result of evaluating expression with comma operator (which basically gives us the last expression in that enumeration - 1).
Note that there's a slight (but very important) difference between list operators/functions and array ones: the former are kind-of omnivores, as they don't change the source data, the latter are not. For example, you can safely slice and join your list, like this:
print join ':', (4,2,3,1)[1,2];
... but trying to 'pop' it will give you quite a telling message:
pop (4, 3, 2, 1);
### Type of arg 1 to pop must be array (not list)...
An array is a type of variable. It contains 0 or more scalars at monotonously increasing indexes. For example, the following creates array #a:
my #a;
Being variables, you can manipulate arrays. You can add elements, change the values of elements, etc.
"List" means many things. The two primary uses for it are to refer to list values and instances of the list operator.
A list value is an ordered collection of zero or more scalars on the stack. For example, the sub in the following code returns a list to be assigned to #a (an array).
my #a = f();
List values can't be manipulated; they are absorbed in whole by any operator to which they are passed. They are just how values are passed between subs and operators.
The list operator (,) is an N-ary operator* that evaluates each of its operands in turn. In list context, the list operator returns a list consisting of an amalgamation of the lists returned by its operands. For example, the list operator in the following snippet returns a list value consisting of all the elements of arrays #a and #b:
my #c = ( #a, #b );
(By the way, parens don't create lists. They're just there to override precedence.)
You cannot manipulate a list operator since it's code.
* — The docs say it's a binary operator (at least in scalar context), but it's not true.
Simple demonstration of difference.
sub getarray{ my #x = (2,4,6); return #x; }
sub getlist { return (2,4,6); }
Now, if you do something like this:
my #a = getarray();
my #b = getlist();
Then #a and #b will both contain the same value - the list (2,4,6). However, if you do this:
my $a = getarray();
my $b = getlist();
Then $a will contain the value 3, while $b will contain the value 6.
So yes, you can say that arrays are variables containing list values, but that doesn't tell the whole story, because arrays and literal lists behave quite differently at times.
Lists are comma-separated values (csv) or expressions (cse) . Arrays (and hashes) are containers.
One can initialize an array or hash by a list:
#a = ("profession", "driver", "salary", "2000");
%h = ("profession", "driver", "salary", "2000");
One can return a list:
sub f {
return "moscow", "tel-aviv", "madrid";
}
($t1, $t2, $t3) = f();
print "$t1 $t2 $t3\n";
($t1, $t2, $t3) is a list of scalar containers $t1, $t2, $t3.
Lists are a form of writing perl expressions (part of syntax) while arrays are data structures (memory locations).
The difference between lists and arrays confuses many. Perl itself got it wrong by misnaming its builtin function wantarray(): "This function should have been named wantlist() instead." There is an answer in perlfaq4, "What is the difference between a list and an array?", but it did not end my confusion.
I now believe these to be true:
An array in scalar context becomes a count of its elements.
The comma operator in scalar context returns the last element.
You can't make a reference to a list; \(2, 4, 6) returns a list of references to the scalars in the list. You can use [2, 4, 6] to make a reference to an anonymous array.
You can index a list (to get its nth element) without making an array if you make a list slice, so (2, 4, 6)[1] is 4.
But what if I want to count the elements in a list, or get the last element of an array? Should I convert between arrays and lists somehow?
You can always convert a list to an array with [...] syntax. One way to count the elements in a list is to make an anonymous array, then immediately dereference it in scalar context, like so:
sub list { return qw(carrot stick); }
my $count = #{[list()]};
print "Count: $count\n"; # Count: 2
Another way is to use the list assignment operator, like so:
sub list { return qw(carrot stick); }
my $count = (()=list());
print "Count: $count\n"; # Count: 2
There is no array in this code, but the list assignment operator returns the number of things being assigned. I assign them to an empty list of variables. In code golf, I write ()=$str=~/reg/g to count the regular expression matches in some string.
You need not convert an array to a list, because an array in list context is already a list. If you want the last element of an array, just say $array[-1].
The comma operator would return the last element of a list, but I can't use it to get the last element of an array. If I say ((),#array) in scalar context, then #array is in scalar context and I get the count.
You need not make an array to index a list. You can make an anonymous array, as in [list()]->[1], or you can make a list slice, as in (list())[1]. I had trouble with list slices because they have different syntax. A list slice needs parentheses! In C or Python or Ruby, func()[1] would do the array index on the function's return value, but in Perl, func()[1] is a syntax error. You must say (func())[1].
For example, I want to print the 3rd highest number in array. Because I'm lazy, I sort the array and take the 3rd last element:
my #array = (112, 101, 114, 108, 32, 104, 97, 99, 107);
print +(sort { $a <=> $b } #array)[-3], "\n"; # prints 108
The unary + prevents the print() function stealing my parentheses.
You can use a list slice on an array, as in (#array)[1]. This works because an array is a list. The difference between lists and arrays is that arrays can do $array[1].
An Array Vs A List
A list is a different kind of data structure from an array.
The biggest difference is in the idea of direct access Vs sequential access. Arrays allow both; direct and sequential access, while lists allow only sequential access. And this is because the way that these data structures are stored in memory.
In addition, the structure of the list doesn’t support numeric index like an array is. And, the elements don’t need to be allocated next to each other in the memory like an array is.
Arrays
An array is an ordered collection of items, where each item inside the array has an index.
here my answer about sigils and context
but main difference is this:
arrays have a scalar-context-value like count of elements.
lists have a scalar-context-value like LAST element in list.
so, you need to know about goat-operator: =()=.
Usage?
perl -e '$s =()= qw(a b c); print $s' # uh? 3? (3 elements, array context)
perl -e '$s = qw(a b cLastElementThatYouSee); print $s' # uh? cLastElementThatYouSee? (list context, last element returned)
as you see, =()= change context to array
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
In Perl, is there a built in way to compare two arrays for equality?
I need to compare arrays with a function that should return:
true if all elements are equal when compared pairwise
true if all elements are equal or the element in the first array is undefined when compared pairwise
false in all other cases
in other words, if the sub is called "comp":
#a = ('a', 'b', undef, 'c');
#b = ('a', 'b', 'f', 'c');
comp(#a, #b); # should return true
comp(#b, #a); # should return false
#a = ('a', 'b');
#b = ('a', 'b', 'f', 'c');
comp(#a, #b); # should return true
the obvious solution would be to do pairwise compares between the two arrays, but I'd like it to be faster than that, as the comparisons are run multiple times over a large set of arrays, the and the arrays may have many elements.
On the other hand, the contents of the arrays to be compared (i.e.: all the possible #b's) is pre-determined and does not change. The elements of the arrays do not have a fixed length, and there is no guarantee as to what chars they might contain (tabs, commas, you name it).
Is there a faster way to do this than pairwise comparison? Smart match won't cut it, as it returns true if all elements are equal (an therefore not if one is undef).
Could packing and doing bitwise comparisons be a strategy? It looks promising when I browse the docs for pack/unpack and vec, but I'm somewhat out of my depth there.
Thanks.
Perl can compare lists of 10,000 pairwise elements in about 100ms on my Macbook, so first thing I'll say is to profile your code to make sure this is actually the problem.
Doing some benchmarking, there's a few things you can do to speed things up.
Make sure to bail on the first failure to match.
Assuming you have a lot of comparisons which don't match, this will save HEAPS of time.
Check up front that the arrays are the same length.
If they arrays aren't the same length, they can never match. Compare their sizes and return early if they're different. This avoids needing to check this case over and over again inside the loop.
Use an iterator instead of a C-style for loop.
Iterating pair-wise you'd normally do something like for( my $idx = 0; $idx <= $#a; $idx += 2 ) but iterating over an array is faster than using a C-style for loop. This is an optimization trick of Perl, its more efficient to do the work inside perl in optimized C than to do it in Perl code. This gains you about 20%-30% depending on how you micro-optimize it.
for my $mark (0..$#{$a}/2) {
my $idx = $mark * 2;
next if !defined $a->[$idx] || !defined $b->[$idx];
return 0 if $a->[$idx] ne $b->[$idx] || $a->[$idx+1] ne $b->[$idx+1];
}
return 1;
Precompute the interesting indexes.
Since one set of pairs is fixed, you can produce an index of which pairs are defined. This makes the iterator even simpler and faster.
state $indexes = precompute_indexes($b);
for my $idx ( #$indexes ) {
next if !defined $a->[$idx];
return 0 if $a->[$idx] ne $b->[$idx] || $a->[$idx+1] ne $b->[$idx+1];
}
return 1;
With no nulls this is a performance boost of 40%. You get more beyond that the more nulls are in your fixed set.
use strict;
use warnings;
use v5.10; # for state
# Compute the indexes of a list of pairs which are interesting for
# comparison: those with defined keys.
sub precompute_indexes {
my $pairs = shift;
die "Unbalanced pairs" if #$pairs % 2 != 0;
my #indexes;
for( my $idx = 0; $idx <= $#$pairs; $idx += 2 ) {
push #indexes, $idx if defined $pairs->[$idx];
}
return \#indexes;
}
sub cmp_pairs_ignore_null_keys {
my($a, $b) = #_;
# state is like my but it will only evaluate once ever.
# It acts like a cache which initializes the first time the
# program is run.
state $indexes = precompute_indexes($b);
# If they don't have the same # of elements, they can never match.
return 0 if #$a != #$b;
for my $idx ( #$indexes ) {
next if !defined $a->[$idx];
return 0 if $a->[$idx] ne $b->[$idx] || $a->[$idx+1] ne $b->[$idx+1];
}
return 1;
}
I'm still convinced this is better to do in SQL with a self-join, but haven't worked that out.
I once read the following example about "array of arrays". AOA is a two dimensional array
The following code segment is claimed to print the whole thing with refs
for $aref ( #AoA ) {
print "\t [ #$aref ],\n";
}
And the following code segment is claimed to print the whole thing with indices
for $i ( 0 .. $#AoA ) {
print "\t [ #{$AoA[$i]} ],\n";
}
What's the $aref stand for here? How to understand the definition of #$aref and #{$AoA[$i]}? Thanks.
$aref stands for "array reference", i.e. a reference for an array.
my $my_aref = \#somearray;
You can make an array from an array reference with the following syntax:
#{$my_aref}
#{$my_aref} is #somearray. (It's not a copy, it really is the same array.)
In second example, $AoA[$i] is an array reference, and you dereference it with the same syntax: #{$AoA[$i]}.
See perlreftut for more explanations and examples.
An "array of arrays" isn't actually an array of arrays. It's more an array of array references. Each element in the base array is a reference to another array. Thus, when you want to cycle through the elements in the base array, you get back array references. These are what get assigned to $aref in the first loop. They are then de-referenced by pre-pending with the # symbol, so #$aref is the array referenced by the $aref array reference.
Same sort of thing works for the second loop. $AoA[$i] is the $i-th element of the #AoA array, which is an array reference. De-referencing it by pre-pending it with the # symbol (and adding {} for clarity, and possibly for precedence) means #{$AoA[$i]} is the array referenced by the $AoA[$i] array reference.
Perl doesn't have multidimensional arrays. One places arrays into other arrays to achieve the same result.
Well, almost. Arrays (and hashes) values are scalars, so one cannot place an array into another array. What one does instead of place a reference to an array instead.
In other words, "array of arrays" is short for "array of references to arrays". Each value of the #AoA is a reference to another array, given the "illusion" of a two-dimensional array.
The reference come from the use [ ] or equivalent. [ ] creates an anonymous array, then creates a reference to that array, then returns the reference. That's where the reference comes from.
Common ways of building an AoA:
my #AoA = (
[ 'a', 'b', 'c' ],
[ 'd', 'e', 'f' ],
);
my #AoA;
push #AoA, [ 'a', 'b', 'c' ];
push #AoA, [ 'd', 'e', 'f' ];
my #AoA;
$AoA[$y][$x] = $n;
Keep in mind that
$AoA[$y][$x] = $n;
is short for
$AoA[$y]->[$x] = $n;
and it's equivalent to the following thanks to autovivification:
( $AoA[$y] //= [] )->[$x] = $n;
The whole mystery with multi-dimension structures in perl is quite easy to understand once you realize that there are only three types of variables to deal with. Scalars, arrays and hashes.
A scalar is a single value, it can contain just about anything, but
only one at the time.
An array contains a number of scalar values, ordered by a fixed
numerical index.
A hash contains scalar values, indexed by keys made of strings.
And all arrays, hashes or scalars act this way. Multi-dimension arrays are no different from single dimension.
This is also expressed very succinctly in perldata:
All data in Perl is a scalar, an array of scalars, or a hash of
scalars. A scalar may contain one single value in any of three
different flavors: a number, a string, or a reference. In general,
conversion from one form to another is transparent. Although a scalar
may not directly hold multiple values, it may contain a reference to
an array or hash which in turn contains multiple values.
For example:
my #array = (1, 2, 3);
Here, $array[0] contains 1, $array[1] contains 2, etc. Just like you would expect.
my #aoa = ( [ 1, 2, 3 ], [ 'a', 'b', 'c' ] );
Here, $array[0] contains an array reference. If you print it out, it will say something like ARRAY(0x398a84). Don't worry! That's still a scalar value. How do we know this? Because arrays can only contain scalar values.
When we do something like
for $aref ( #AoA ) {
print $aref; # prints ARRAY(0x398a84) or similar
}
It's no different from doing
for $number ( #array ) {
print $number;
}
$aref and $number are scalar values. So far, so good. Take a moment and lock this knowledge down: Arrays can only contain scalar values.
Now, the next part is simply knowing how to deal with references. This is documented in perlref and perlreftut.
A reference is a scalar value. It's an address to a location in memory. This location contains some data. In order to access the actual data, we need to dereference the reference.
As a simple example:
my #data = (1, 2, 3);
my $aref = \#data; # The backslash in front of the sigil creates a reference
print $aref; # print something like ARRAY(0xa4b6a4)
print #$aref; # prints 123
Adding a sigil in front of the reference tells perl to dereference the scalar value into the type of data the sigil represents. In this case, an array. If you choose the wrong sigil for the type of reference, perl will give an error such as:
Not a HASH reference
In the example above, we have a reference to a specific, named location. Both #$aref and #data access the same values. If we change a value in one, both are affected, because the address to the memory location is identical. Let's try it:
my #data = (1, 2, 3);
my $aref = \#data;
$$aref[1] = 'a'; # dereference to a scalar value by $ sigil
# $aref->[1] = 'a' # does the same thing, a different way
print #data; # prints 1a3
print #$aref; # prints 1a3
We can also have anonymous data. If we were only interested in building an array of arrays, we'd have no interest in the #data, and could skip it by doing this:
my $aref = [ 1, 2, 3 ];
The brackets around the list of numbers create an anonymous array. $aref still contains the same type of data: A reference. But in this case, $aref is the only way we have of accessing the data contained at the memory location. Now, let's build some more scalar values like this:
my $aref1 = [ 1, 2, 3 ];
my $aref2 = [ 'a', 'b', 'c' ];
my $aref3 = [ 'x', 'y', 'z' ];
We now have three scalar variables that contain references to anonymous arrays. What if we put these in an array?
my #aoa = ($aref1, $aref2, $aref3);
If we'd want to access $aref1, we could do print #$aref1, but we could also do
print #{$aoa[0]};
In this case, we need to use the extended form of dereferencing: #{ ... }. Because perl does not like ambiguity, it requires us to distinguish between #{$aoa[0]} (take the reference in $aoa[0] and dereference as an array) and #{$aoa}[0] (take the reference in $aoa and dereference as an array, and take that arrays first value).
Above, we could have used #{$aref}, as it is identical to #$aref.
So, if we are only interested in building an array of arrays, we are not really interested in the $aref1 scalars either. So let's cut them out of the process:
my #aoa = ( [ 1, 2, 3 ], [ 'a', 'b', 'c' ], [ 'x', 'y', 'z' ]);
Tada! That's an array of arrays.
Now, we can backtrack. To access the values inside this array, we can do
for my $scalar ( #aoa ) {
print #$scalar; # prints 123abcxyz
}
This time, I used a different variable name, just to make a point. This loop takes each value from #aoa -- which still is only a scalar value -- dereferences it as an array, and prints it.
Or we can access #aoa via its indexes
for my $i ( 0 .. $#aoa ) {
print #{$aoa[$i]};
}
And that's all there is to it!