Sunday, May 1, 2011

Perl - How to access and array element that's held within another array

Heylo again,

I've been trying to make my program somewhat easier to maintain. I have an array which I declare:

my @pizza = ($p1 = "Pizza One", $p2 = "Pizza Two" );

I then go ahead and put this @Pizza array in another array, like so:

my @food = (\@pizza);

When I attempt to access either $p1 or $p2 via the @food property I get a value returned like "Array{0x8001}" which appears to be a memory reference. What i tried was this:

$test = ${$food[$pizza[$p1]]};

What is the corret way to access this? I am looking to NOT use indexes in order to ease program readability. could you guys point me in the right direction?

Regards,


This is what I am trying to do:

I have several databases (for talks sake this is an example)

Database One
Table One (D1T1) | Column One | Column Two | Column Three | Column Four
Table Two (D1T2) | Column One | Column Two | Column Three

Database Two
Table One (D2T1) | Column One | Column Two| Column Three
Table Two (D2T2) | Column One | Column Two| Column Three
Table Three (D2T2) | Column One | Column Two| Column Three

Between these two databases there is information that is relative to particular records right across them both. What I am trying to do is create an array (each array will represent a database) and insert variables (each variable will represent a table.field. within the datasource) Once I have done this I am creating an array to hold all teh arrays (The ones that represent the db's) as this array will represent a single entry right across the two databases which I can then act on. Example:

@D1 = ( t1.col1, t1.col4, t2.col1 ); @D2 = ( t1.col1, t2.col1, t3.col2, t3.col3);

@rec = ( \@D1, \@D2 );

If I want to know what was held in Database 2 -> Table 2 -> Column 4 what would the statement be? Should I be using hashes instead? I do have a requirement for this two dimensional array/hash.

Any help is much appreciated.

MC

From stackoverflow
  • Not knowing what you're trying to accomplish, what data you're modeling, all I can help you with is the syntax confusion. There's confusion here on several points.

    # You wrote
    my @pizza = ($p1 = "Pizza One", $p2 = "Pizza Two" );
    

    That does not do what you mean. It makes the array ("Pizza One", "Pizza Two") but it also sets $p1 to be Pizza One and $p2 to be Pizza Two. I think you're trying to assign Pizza One to the key p1. I think you want to use a hash/associated array:

    # Try a hash
    my %pizzas = (p1 => "Pizza One", p2 => "Pizza Two");
    

    Now $pizzas{p1} is Pizza One. Alternatively, just make a list:

    # An array
    my @pizzas = ("Pizza One", "Pizza Two");
    

    And then $pizzas[0] is Pizza One. Moving on...

    # You wrote
    my @food = (\@pizza);
    

    You're trying to make another list refer to @pizza. The above makes $food[0] reference to @pizza which is not what you meant. References in Perl are scalars and have different syntax.

    # What you probably meant
    my $food = \@pizza;
    

    Now $food->[0] is Pizza One and $food->[0] is Pizza Two.

    # You wrote
    $test = ${$food[$pizza[$p1]]};
    

    Smacks of just adding more braces until you got output. I'd recommend reading the Perl Data Structures Cookbook. Oh, and turn on warnings. Don't turn them off until they all go away and don't turn them off because there's too many of them. Really. Really really.

    Update

    "I want to know what was held in Database 2 -> Table 2 -> Column 4 what would the statement be?"

    Don't use numbers. Name them, because I'm sure they have names. So yes, you want hashes. So let's say Database Foo -> Table Bar -> Column Baz. You'd access that like...

    $values = $databases->{Foo}{Bar}{Baz};
    

    or long hand

    $tables  = $databases->{Foo};
    $columns = $tables->{Bar};
    $values  = $columns->{Baz};
    

    Where $values can be an array ref of all the values of Foo.Bar.Baz, or another hash keyed by the primary key of Foo.Bar. Which makes more sense depends on what you're doing to do with the data.

    I'll leave it to you to adapt Chaz's answer to generate hashes instead of arrays.

    Of course, I must ask why dump the whole of both databases out into a big in-memory structure and then work on it? If you have databases, query them. It'll be faster and more flexible.

    We're back to that most basic of questions; what is it you're REALLY trying to do?

    cjm : I think he means he doesn't want a lot of magic numbers sprinkled through his code (like $object[1]), for which the solution is either a hashref instead of an arrayref, or "use constant" or "use enum" to declare constants for your field indexes.
    Schwern : Ahh, I misparsed it as "I am NOT looking to use indexes..."
  • Based on what you described is sounds like you need something like this:

    #!/usr/bin/perl
    
    use strict;
    use warnings;
    
    my @dbs;
    while (<DATA>) {
        chomp;
        if (/^Database/) {
            push @dbs, [];
            next;
        }
        my @table = split /\s*\|\s*/;
        push @{$dbs[-1]}, [ @table[1 .. $#table] ];
    }
    
    print "datbase 1, table 2, column 1: $dbs[0][1][0]\n";
    
    for my $db (0 .. $#dbs) {
        for my $table (0 .. $#{$dbs[$db]}) {
            for my $col (0 .. $#{$dbs[$db][$table]}) {
                print "($db,  $table, $col) is $dbs[$db][$table][$col]\n";
            }
        }
    }
    
    
    __DATA__
    Database One
    Table One (D1T1) | D1T1C1 | D1T1C2 | D1T1C3 | D1T1C4
    Table Two (D1T2) | D1T2C1 | D1T2C2 | D1T2C3
    
    Database Two
    Table One (D2T1)   | D2T1C1 | D2T1C2 | D2T1C3
    Table Two (D2T2)   | D2T2C1 | D2T2C2 | D2T2C3
    Table Three (D2T2) | D2T3C1 | D2T3C2 | D2T3C3
    

0 comments:

Post a Comment