BioNrd has asked for the wisdom of the Perl Monks concerning the following question:

EDIT: It was nearly 1 in the morning when I posted. Looking now, really against my better judgment. I was tired and frustrated.

I apologize, sometimes i forget that monks are mere mortals, not programing gods that can read my mind.

The advice to slow down and think goes a long way. I appreciate that greatly. I solved the one issue relating to getting the hash reference, but still have the issue with the flexible naming. See comments inside the code. I may have a solution, but I am not confident in it.

use Data::Dumper; use warnings; my @array_1 = (1 .. 10); my @array_2 = (1 .. 10); my $internal_hash_number = 2; for (1 .. $internal_hash_number) { my $internal_name = $_; my @hold_a; my @hold_b; my $min = 10; my $max = 50; for (1 .. 10) { my $internal_value_a = int rand($max - $min + 1) + $min; push(@hold_a, $internal_value_a); my $internal_value_b = int rand($max - $min + 1) + $min; push(@hold_b, $internal_value_b); } $internal_hash{$internal_name} = { "$internal_name\_a" => [@hold_a], "$internal_name\_b" => [@hold_b], }; } $storage_hash{1} = { holder => [@array_1], individual => [ @array_2 ], marker => [ %internal_hash ], }; print Data::Dumper->Dumpxs([\%storage_hash], [q{*storage_hash}]); #now: #this accesses the array within the hash: my @external_array = @{$storage_hash{1}{'holder'}}; print "@external_array\n"; #this accesses the hash within the hash: my %internal_hash_ref = @{$storage_hash{1}{'marker'}}; my $internal_ref_name = '1_a'; my @internal_array_ref = @{$internal_hash_ref{1}{$internal_ref_name}}; print "@internal_array_ref\n"; @internal_array_ref[1] = 20; print "@internal_array_ref\n"; $internal_hash_ref{1}{$internal_ref_name} = [@internal_array_ref]; print Data::Dumper->Dumpxs([\%internal_hash_ref], [q{*internal_hash_re +f}]); # This gives me the array back out that I can now do things with. # BUT I want to be able to have a code that is flexable... # So that I can change the number of $internal_hash_number... # and the code will be... # smart enough to name the array based on... # what it is called in the hash. my $value = 0; for (1 .. $internal_hash_number) { $value++; my $safe_input = $value; print "$safe_input\n"; @{$safe_input}=(); push @{$safe_input}, @{$internal_hash_ref{1}{$internal_ref_name}}; print "@{$safe_input}\n"; } #do you monks think that this is a valid bit of code? #or should I not do it like this?
One other thing: I am however confused about the <TABS> how on earth do you read code that is not tabbed? I cant understand it, it looks like run on sentences to me. Though I am still new to this, maybe it comes with experience.

Replies are listed 'Best First'.
Re: HwithinHoA? Complex Data Structure...I am so lost...
by wfsp (Abbot) on Dec 14, 2007 at 07:50 UTC
    I agree with perlfan. If you try to run your code with use strict perl complains that the script has "too many errors". This is mainly because you aren't declaring all your variables. For instance, right at the begining change it to
    my $popCt = 1; my $markers = 2;
    This will help, amoung other things, track down typos. In tester() you have $HoHMarer where you almost certainly mean $HoHMarker. Nail down those sort of errors and you are often halfway there.

    I find it easier to track down bugs by supplying a sub all the arguments it needs so that it is a self contained script on its own. This means you can test it on its own, it doesn't rely on anything that might be happening a hundred lines further up or further down the script. This way you can test your script with sample known good/bad data and check that it behaves as expected.

    Again in tester(), the first three lines are

    sub tester { my @holder = @{$HoH{$newcounter}{'holder'}}; my @ind = @{$HoH{$newcounter}{'individual'}}; my %HoHMarker = %{$HoH{$newcounter}{'marker'}};
    What do you expect $newcounter to be? undef would not be a lot of use here. Strict would force you to declare it and you may need it to be an argument that you pass to the sub.

    my $newcounter = 1; tester($newcounter); #... sub tester { my ($newcounter) = @_; ... }
    Pass your subs all the args it needs. If it needs a lot construct a hash/hashref.
    my $args = { arg1 => $arg1, arg2 => $arg2, arg3 => $arg3, }; tester($args); ... sub tester{ my ($args) = @_; ... }
    You could also debate how useful %HOH is as a name, something more meaningful (but short) might make the code easier to read.

    Some more error checking wouldn't go amiss and Data::Dumper is, as you have, a very useful tool. When I'm trying to get some sense out of a script I use the ... or die "somevar is $somevar"; liberally, and when things are really bad on everyother line. :-)

    As an example, in tester() again

    sub tester { my @holder = @{$HoH{$newcounter}{'holder'}}; die "tester: holder is empty" unless @holder;
    Have all your subs return a value. Even if it is only true on success and false on failure. The "return early, return often" idiom can make your subs logic a lot easier too. It would also assist testing/error checking.
    my $success = tester(); die "tester failed" unless $success;
    Finally,
    ...is there a way to have an array name itself...
    With strict and warnings on the answer is "no". Self modifying code is considered a bad idea but there are many alternatives, a hash lookup being popular.

    my %user_data_lookup; ... my $safe_input = validate($user_input); push @{$user_data_lookup{$safe_input}}, @some_array; ...
    Try to write a script that demonstrates the snag you're having trouble with (not the whole lot!) and we'll see where we go from there.

    Good luck! Let us know how you get on.

Re: HwithinHoA? Complex Data Structure...I am so lost...
by perlfan (Parson) on Dec 14, 2007 at 05:39 UTC
    Would you boil down your question a tad so that mere mortals can understand what your asking? In doing so, you may even figure out the answer yourself. A lot of the craziness you're trying to do is most likely unnecessary. Also, letting users determine variable names at run time is probably a very bad idea.
Re: HwithinHoA? Complex Data Structure...I am so lost...
by johngg (Canon) on Dec 14, 2007 at 11:09 UTC
    Adding to the points made by wfsp, your sub tester as posted doesn't look as if it will compile as you have a mismatch with your braces (too many of the right-hand type). I don't know what tools you use to develop your code but an editor that shows matching parentheses and braces can be very useful when trying to weed out this sort of error. I use nedit

    Staying with tester, what are you actually trying to iterate over with foreach $new_marker(%HoHMarker) { ...? You can't really iterate over a hash like that; do you mean to iterate over an array contained in that hash?

    Without wanting to re-ignite a religeous war, your use of <TABS> to indent your code makes life difficult unless you are working in Super Panorama. Also, indenting only really works if it is applied consistently.

    For your user-determined variable names, use a hash.

    @{ $userHash{ $newName } } = @array;

    I hope this is useful.

    Cheers,

    JohnGG

Re: HwithinHoA? Complex Data Structure...I am so lost...
by wfsp (Abbot) on Dec 15, 2007 at 08:59 UTC
    You shouldn't overwrite you post. Anyone looking at this thread now won't understand the comments that have been made. You should post a new note in the thread with your new code and add a comment to your original post explaining that you have posted new a note (perhaps with a link to the new note).

    You still haven't added

    use strict;
    to the top of your code. If you had you would have seen that it is still throwing errors.

    Declaring all your variables fixes most of them. There was a syntax snag (not exactly an error)

    #@internal_array_ref[1] = 20; # better as $internal_array_ref[1] = 20;
    As to the question at the end of the script.
    I want to be able to have a code that is flexible. So that I can change the number of internal_hash_number and the code will be smart enough to name the array based on what it is called in the hash.
    In the hash you are looking at you have primary and secondary keys. Each secondary key points to an array ref. You can iterate over it by
    for my $key_primary (keys %internal_hash_ref) { print qq{primary key: *$key_primary*\n}; for my $key_secondary (keys %{$internal_hash_ref{$key_primary}}){ print qq{\tsecondary key: *$key_secondary*\n}; print qq{\t\t*@{$internal_hash_ref{$key_primary}{$key_secondary}}* +\n}; } }
    output:
    primary key: *1* secondary key: *1_b* *34 33 49 32 46 47 27 31 46 30* secondary key: *1_a* *44 20 20 32 32 47 39 35 24 41* primary key: *2* secondary key: *2_a* *34 23 24 30 10 38 47 23 17 25* secondary key: *2_b* *45 47 44 44 45 39 13 35 14 23*
    So, @{$internal_hash_ref{$key_primary}{$key_secondary}} is the name of the array. If this isn't what you want you will have to explain a bit more what it is you want to do with this "named" array.

    Don't overwrite your posts and use strict and warnings.

    Good luck!