13

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)  
Luke
  • 327
  • 2
  • 7
  • 15
  • 2
    possible duplicate of http://stackoverflow.com/questions/2360192/how-to-print-one-array-of-a-multidimensional-array-in-perl – Eric Strom May 18 '10 at 19:36
  • SO 2360192 is loosely related to this, but the trigger here is explicit '`[...]`' notation and in the other it is much less direct. – Jonathan Leffler May 18 '10 at 19:44

3 Answers3

20

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->[2]."\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 print "@$_\n" for @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
  • 36,680
  • 16
  • 86
  • 155
4

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
  • 730,956
  • 141
  • 904
  • 1,278
  • 3
    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 May 18 '10 at 19:51
  • 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 May 18 '10 at 20:03
-2

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
  • 17,054
  • 13
  • 68
  • 116
  • 2
    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 May 18 '10 at 20:59
  • @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 May 18 '10 at 21:42
  • 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 May 18 '10 at 21:59
  • 1
    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 May 19 '10 at 02:16