4

What is the difference when you use () in Perl versus [] for example and how do you find the size of the array when it uses the square brackets?

my @myarr = ( # Parenthesis
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
               );

my @myarr = [ # Square bracket
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
               ];

Thank you for the explanations. I am still trying to understand this, and it's just slightly confusing to me at the moment. I still can't figure out how to iterate through my data here:

#!/usr/bin/perl -w

use strict;
use FindBin qw($Bin);
use Cwd;
use Data::Dumper;

my @mynames = (
                [ "myname", "mydescription", "mydata"],
                [ "myname2", "mydescription2", "mydata2"],
                [ "myname3", "mydescription3", "mydata3"],
               );


go();

sub go {
    start(\@mynames);
}

sub start {
    my @input_name = shift;

    # This works
    #print @input_name->[0][0][0];
    #die;

    # This Shows
    #print Dumper(@input_name);
    #$VAR1 = [
    #          [
    #            'myname',
    #            'mydescription',
    #            'mydata'
    #          ],
    #          [
    #            'myname2',
    #            'mydescription2',
    #            'mydata2'
    #          ],
    #          [
    #            'myname3',
    #            'mydescription3',
    #            'mydata3'
    #          ]
    #        ];

    # How do I iterate?
    #for my $i (0..@$input_name) {
    #    my $name = "";
    #    my $description = "";
    #    my $data = "";
    #
    #}
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user391986
  • 29,536
  • 39
  • 126
  • 205

4 Answers4

6

This is wrong:

my @myarr = [
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
               ];

It should be either:

my $myarr = [
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
               ];

It is "$myarr" above. The square bracket will return a reference to a list which is a scalar. Hence need to use "$" instead of "@".

Or

my @myarr = (
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
               );

It is "()" above instead of "[]". The "()" will return the list and hence it needs "@".

Check the below code which iterates over the AoA. This way you can access all the elements of the AoA. As well as individual elements:

#!/usr/bin/perl -w
use strict;

my @mynames = (
                [ "myname", "mydescription", "mydata"],
                [ "myname2", "mydescription2", "mydata2"],
                [ "myname3", "mydescription3", "mydata3"],
              );

### To access all the elements in above AoA
foreach my $a (@mynames)
{
    foreach my $b ( @{$a} )
    {
        print $b."\t";
    }
    print "\n";
}
print "====================================\n";

### To access individual elements:
print $mynames[1][2]."\n"; ### It prints mydata2

You may want to read perlref to learn and understand Perl reference and nested data structure.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
slayedbylucifer
  • 22,878
  • 16
  • 94
  • 123
2

Parentheses don't create arrays, or even lists. Let's show a meaningful comparison of your code:

my @myarr1 = (
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
             );

my @myarr2 = (
                [
                   [ "itemone", "itemoneb", "itemonec" ],
                   [ "itemtwo", "itemtwob", "itemtwoc" ]
                ],
             );

@myarr1 is an AoA with two elements.
@myarr2 is an AoAoA with one element.

To find the size of the array referenced by $myarr2[0], you'd use the following in a scalar context:

@{ $myarr2[0] }

That said, you probably meant to use

my $myarr2 = [
                [ "itemone", "itemoneb", "itemonec" ],
                [ "itemtwo", "itemtwob", "itemtwoc" ]
             ];

In which case, you'd use the following in a scalar context:

@$myarr2     # Short for @{ $myarr2 }
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ikegami
  • 367,544
  • 15
  • 269
  • 518
1

This is an answer to the updated question, which is about how to iterate through the multidimensional array

Array of arrays

my @mynames = (
    [qw(myname  mydescription  mydata )], # the same as 'myname', 'my...', ...
    [qw(myname2 mydescription2 mydata2)],
    [qw(myname3 mydescription3 mydata3)],
);

(As the comment states, qw(foo bar) is just a fancy way to write 'foo', 'bar'.) This is basically an AoA (array of arrays), which can be used like this:

Dumb iterating

foreach my $row (@mynames) {
    foreach my $col (@$row) {
        say $col;
    }
    say 'done with this row';
}

Output:

myname
mydescription
mydata
done with this row
myname2
mydescription2
mydata2
done with this row
myname3
mydescription3
mydata3
done with this row

But we do know a little bit more about this AoA:

Not that dumb iterating

foreach my $row (@mynames) {
    say join ', ' => @$row;
}

Output:

myname, mydescription, mydata
myname2, mydescription2, mydata2
myname3, mydescription3, mydata3

$row is an array reference and to use its list value in join, we have to dereference it with @$row. But we can do better:

We know more about the structure here

foreach my $row (@mynames) {
    say "name: $row->[0], description: $row->[1], data: $row->[2]";
}

Output:

name: myname, description: mydescription, data: mydata
name: myname2, description: mydescription2, data: mydata2
name: myname3, description: mydescription3, data: mydata3

We know that the first item is a name, the second is a description and the third is some kind of a data value, so we can simply tell the user this fact in our output. $row->[42] is the way to access a single value in an array ref, compared to do the same with a simple array $array[42].

But we can do better!

Hash of hashes

As we know that much about our structure, it's much better to use an hash of hashes (HoH) to express this structure. Since the first item seems to be some kind of a (hopefully unique) name of the rest, we can use it for our hash keys, while description and data go into a new hash reference:

my %data = (
    myname  => {description => 'foo', data => 42},
    myname2 => {description => 'bar', data => 17},
    myname3 => {description => 'baz', data => 37},
);

Iterating over the data now feels now much better and the code is more readable and robust:

foreach my $name (keys %data) {
    say "name       : $name";
    say "description: $data{$name}{description}";
    say "data       : $data{$name}{data}";
}

Output:

name       : myname
description: foo
data       : 42
name       : myname3
description: baz
data       : 37
name       : myname2
description: bar
data       : 17

However, as you can see, the output isn't ordered anymore. Maybe this isn't a problem, but if you want to define an order, you can do it with sort. With this flexible construct you can for example order by some specific data value:

Order by data

foreach my $name (sort {$data{$a}{data} <=> $data{$b}{data}} keys %data) {
    say "name       : $name";
    say "description: $data{$name}{description}";
    say "data       : $data{$name}{data}";
}

Output:

name       : myname2
description: bar
data       : 17
name       : myname3
description: baz
data       : 37
name       : myname
description: foo
data       : 42

Read more about how this works in perldoc -f sort.

Array of hashes

If your names aren't unique, you can use an array of hashes like this:

my @data = (
    {name => 'myname', description => 'mydescription', data => 'mydata'},
    # ...
);

I leave it as a simple exercise for the reader how to operate on this structure. Hope it helps!

More to read

perlreftut - MJD's very short tutorial about references
perlref - Perl references and nested data structures
perldsc - perl data structures cookbook

memowe
  • 2,656
  • 16
  • 25
0

Square brackets [] create a reference to a list whereas parentheses creates just a list.

A reference is like a pointer in that is has to be dereferenced to obtain the list it references. A reference is a scalar value which means you can store it in a scalar variable. You use the @ prefix to dereference a list reference which will give you back a list.

You can also create references by using the \ operator, e.g.:

[ a,b,c ] is the same as \@a if @a = (a,b,c)

Examples:

my $a = [5,3,1];    # @$a is the same as (5,3,1)
push(@$a, 10);      # @$a is now (5,3,1,10)
join('-', @$a);     # "5-3-1-10"

say $a->[1];        # Prints "3" - an example of indexing
say $$a[1];         # Also prints "3"

sub foo { my $x = shift; say "Your list has ", scalar(@$x), " elements" }

foo($a);            # Prints: Your list has 4 elements

sub same_length { my ($x, $y) = @_; scalar(@$x) == scalar(@$y) }

same_length( $a, [6,7,8] );    # Returns false
same_length( $a, $a );         # Returns true

Note in the same_length example how we passed two lists (by using references) to a subroutine. This is one of the main reasons to use references.

toolic
  • 57,801
  • 17
  • 75
  • 117
ErikR
  • 51,541
  • 9
  • 73
  • 124