tags:

views:

291

answers:

4

What does it mean when you try to print an array or hash and you see the following; Array(0xd3888) or HASH(0xd3978)?

EXAMPLE

CODE

my @data = (  
['1_TEST','1_T','1_TESTER'],  
['2_TEST','2_T','2_TESTER'],  
['3_TEST','3_T','3_TESTER'],  
['4_TEST','4_T','4_TESTER'],  
['5_TEST','5_T','5_TESTER'],  
['6_TEST','6_T','^_TESTER']  
);  

foreach my $line (@data) {  
   chomp($line);  
   @random = split(/\|/,$line);  
   print "".$random[0]."".$random[1]."".$random[2]."","\n";  
}  

RESULT

ARRAY(0xc1864)  
ARRAY(0xd384c)  
ARRAY(0xd3894)  
ARRAY(0xd38d0)  
ARRAY(0xd390c)  
ARRAY(0xd3948)  
A: 

0x indicates a hex number.

Often in messages like that, you're seeing the address in memory the Object references.

glowcoder
This doesn't seem very perl-specific; if you see `ARRAY(0x...)` (or `HASH(...)`, or whatever), you are definitely seeing a stringified reference.
Jefromi
@Jefromi: Well, it's technically correct. It's just not very helpfu. Perhaps glowcoder is an engineer by trade. ;)
Robert P
@both Yep, I'm not a perl guy... just trying to offer some insight where I can! I'm actually more of a Java guy *sadface*...
glowcoder
Does it seem unclear that he was trying to access the value stored behind that reference? That Perl thwarted his perfectly reasonable expectation that $line[0] inside his foreach block would work like it does outside of a foreach? To explain that the $line is magically implemented as a reference (or something sorta like a reference, but called an "alias" in the Perl Syntax man page)?I understand that this behavior in Perl is historical (the syntax worked a given way, before Perl supported references, to allow assignments to lvalues inside the loop in a seemingly reasonable way).
Jim Dennis
@Jim, there wouldn't be any difference in the contents of `$line[0]` in or out of a for loop. He's getting references back because that's what he put into the array using the brackets in defining the values in `@data`. There's no magic at play and getting something out of `@data` besides what he put in isn't a reasonable expectation; it's a casual slip-up.
cikkle
Moreover even if he'd gotten that part right, as Zaid noted, he'd still be trying to feed an array into `chomp` and `split` which both expect a scalar string. This code is very confused.
cikkle
Wow, I didn't mean to start an argument. I didn't even downvote the answer. I just wanted to give glowcoder a ping so the answer could get revised or deleted as appropriate.
Jefromi
@All, yes, I forgot to mention that his chomp and split were non-sensical; though I'd noticed them as that he was confused about the sort of data in his @data.
Jim Dennis
No enmity here. Also to amend that last part, chomp can accept a list, but it's still useless in the context of this example.
cikkle
+3  A: 

It means you do not have an array; you have a reference to an array.

Note that an array is specified with round brackets - as a list; when you use the square bracket notation, you are creating a reference to an array.

foreach my $line (@data)
{
    my @array = @$line;
    print "$array[0] - $array[1] - $array[2]\n";
}

Illustrating the difference:

my @data = (
['1_TEST','1_T','1_TESTER'],
['2_TEST','2_T','2_TESTER'],
['3_TEST','3_T','3_TESTER'],
['4_TEST','4_T','4_TESTER'],
['5_TEST','5_T','5_TESTER'],
['6_TEST','6_T','^_TESTER']
);

# Original print loop
foreach my $line (@data)
{
    chomp($line);
    @random = split(/\|/,$line);
    print "".$random[0]."".$random[1]."".$random[2]."","\n";
}

# Revised print loop
foreach my $line (@data)
{
    my @array = @$line;
    print "$array[0] - $array[1] - $array[2]\n";
}

Output

ARRAY(0x62c0f8)
ARRAY(0x649db8)
ARRAY(0x649980)
ARRAY(0x649e48)
ARRAY(0x649ec0)
ARRAY(0x649f38)
1_TEST - 1_T - 1_TESTER
2_TEST - 2_T - 2_TESTER
3_TEST - 3_T - 3_TESTER
4_TEST - 4_T - 4_TESTER
5_TEST - 5_T - 5_TESTER
6_TEST - 6_T - ^_TESTER
Jonathan Leffler
Your example with arrays inside arrays doesn't make any sense. They're just going to get flattened together into a big mush - that's why you have to use references.
rjh
I've edited the example so it doesn't try the () notation. The comments now don't make much sense since they refer to that which is not on show.
Jonathan Leffler
+11  A: 

It's hard to tell whether you meant it or not, but the reason why you're getting array references is because you're not printing what you think you are.

You started out right when iterating over the 'rows' of @data with:

foreach my $line (@data) { ... }

However, the next line is a no-go. It seems that you're confusing text strings with an array structure. Yes, each row contains strings, but Perl treats @data as an array, not a string.

split is used to convert strings to arrays. It doesn't operate on arrays! Same goes for chomp (with an irrelevant exception).

What you'll want to do is replace the contents of the foreach loop with the following:

foreach my $line (@data) {

    print $line->[0].", ".$line->[1].", ".$line->[0]."\n";
}

You'll notice the -> notation, which is there for a reason. $line refers to an array. It is not an array itself. The -> arrows deference the array, allowing you access to individual elements of the array referenced by $line.

If you're not comfortable with the idea of deferencing with arrows (and most beginners usually aren't), you can create a temporary array as shown below and use that instead.

foreach my $line (@data) {

    my @random = @{ $line };
    print $random[0].", ".$random[1].", ".$random[2]."\n";
}

OUTPUT

1_TEST, 1_T, 1_TESTER
2_TEST, 2_T, 2_TESTER
3_TEST, 3_T, 3_TESTER
4_TEST, 4_T, 4_TESTER
5_TEST, 5_T, 5_TESTER
6_TEST, 6_T, ^_TESTER

A one-liner might go something like map { print "@$_\n" } @data; (which is a bit OTT), but if you want to just print the array to see what it looks like (say, for debugging purposes), I'd recommend using the Data::Dump module, which pretty-prints arrays and hashes for you without you having to worry about it too much.

Just put use Data::Dump 'dump'; at beginning of your script, and then dump @data;. As simple as that!

Zaid
A: 

You're printing a reference to the hash or array, rather than the contents OF that.

In the particular code you're describing I seem to recall that Perl automagically makes the foreach looping index variable (my $line in your code) into an "alias" (a sort of reference I guess) of the value at each stage through the loop.

So $line is a reference to @data[x] ... which is, at each iteration, some array. To get at one of the element of @data[0] you'd need the $ sigil (because the elements of the array at @data[0] are scalars). However $line[0] is a reference to some package/global variable that doesn't exist (use warnings; use strict; will tell you that, BTW).

[Edited after Ether pointed out my ignorance] @data is a list of anonymous array references; each of which contains a list of scalars. Thus you have to use the sort of explicit de-referencing I describe below:

What you need is something more like:

print ${$line}[0], ${$line}[1], ${$line}[2], "\n";

... notice that the ${xxx}[0] is ensuring that the xxx is derefenced, then indexing is performed on the result of the dereference, which is then extracted as a scalar.

I testing this as well:

print $$line[0], $$line[1], $$line[2], "\n";

... and it seems to work. (However, I think that the first form is more clear, even if it's more verbose).

Personally I chalk this up to yet another gotchya in Perl.

[Further editorializing] I still count this as a "gotchya." Stuff like this, and the fact that most of the responses to this question have been technically correct while utterly failing to show any effort to actually help the original poster, has once again reminded me why I shifted to Python so many years ago. The code I posted works, of course, and probably accomplishes what the OP was attempting. My explanation was wholly wrong. I saw the word "alias" in the `perlsyn` man page and remembered that there were some funky semantics somewhere there; so I totally missed the part that [...] is creating an anonymous reference. Unless you drink from the Perl Kool-Aid in deep drafts then even the simplest code cannot be explained.
Jim Dennis
Please re-read [perldoc perlreftut](http://perldoc.perl.org/perlreftut.html), [perldoc perldsc](http://perldoc.perl.org/perldsc.html) and [perldoc perllol](http://perldoc.perl.org/perllol.html) if you think this is a "gotcha". The fact that the foreach iterator is a reference to the original data is not relevant to the problem here.
Ether
@Ether: In other words it was more obscure than I thought. Updating my post with a different interpretation of what's going on.
Jim Dennis
@Jim: awesome; I've removed my downvote.
Ether
I should really read six different documents to get a handle on what's happening in five lines of relatively simple code? An none of the Perl mongers here were willing to look past the superficial part of the posting to attempt to explain *why* he was getting references and *how* to de-reference them. (Reminds me of the old adage about posting wrong info to USENet when you want to get a correct answer).
Jim Dennis
@Jim, are you trolling? There are two answers that explain why he gets references and how to de-ref them, both older than your post. Also, you wouldn't need to read all **three** (where did six come from?) of the docs Ether linked. `perlreftut` is a references tutorial and should be plenty to answer the specific question. The second doc is the `Data Structures Cookbook` which shows examples of how to create and access many different compound structures, it alone could answer your question. The third doc is a tutorial for working on lists of lists, it, too, provides the information you needed.
daotoad