http://www.perlmonks.org?node_id=1065408

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

I have this structure saved in this array @edits:
my @edits = @{ $timestamps{$page} } ; print Dumper @edits; $VAR1 = [ '2013-08-18T20:43:40Z' ]; $VAR2 = [ '2013-08-18T20:43:12Z' ]; $VAR3 = [ '2013-08-18T20:17:13Z' ]; $VAR4 = [ '2013-08-18T20:14:02Z' ]; $VAR5 = [ '2013-05-30T19:07:17Z' ];
How do I dereference it? I have tried this:
print join('|'), @$edits, "\n"; Global symbol "$edits" requires explicit package name at ...
TIA

Update: I am overwhelmed by your support. Thanks to you all for your excellent and prompt answers.

Replies are listed 'Best First'.
Re: dereference array
by tobyink (Canon) on Dec 03, 2013 at 13:24 UTC

    @$edits tries to use a variable $edits as an arrayref - i.e. it's unrelated to the @edits variable you've defined. Thus it complains about $edits being undeclared. (That's what the slightly obscure "requires explicit package name" error means.)

    @edits is an array; each item in that array is a reference to another array with only one item, which is a formatted date string.

    You can access these strings like this:

    print $edits[0][0], "\n"; print $edits[1][0], "\n"; # etc

    You could print them pipe-delimited like this:

    print join('|', map $_->[0], @edits), "\n";

    Or you could define @edits more usefully:

    my @edits = map $_->[0], @{ $timestamps{$page} } ; print Dumper @edits; print join('|', @edits), "\n";
    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re: dereference array
by GrandFather (Saint) on Dec 03, 2013 at 13:33 UTC

    timestamps is a hash containing at least one element that is an array reference. The array reference contains 5 elements containing array references. That is a horrible way to describe the structure so lets look at some code ways of dealing with it

    use strict; use warnings; my %timestamps = ( x => [ ['2013-08-18T20:43:40Z'], ['2013-08-18T20:43:12Z'], ] ); my $page = 'x'; my @edits = @{$timestamps{$page}}; for my $stamps (@edits) { for my $stamp (@$stamps) { print "a: $stamp\n"; } } print "b: $edits[0][0]\n"; print "b: $edits[1][0]\n"; print "c: $timestamps{x}[0][0]\n"; print "c: $timestamps{x}[1][0]\n";

    Prints:

    a: 2013-08-18T20:43:40Z a: 2013-08-18T20:43:12Z b: 2013-08-18T20:43:40Z b: 2013-08-18T20:43:12Z c: 2013-08-18T20:43:40Z c: 2013-08-18T20:43:12Z

    I've only populated two of the time stamps, but that should serve to see how things hand together. Note the {} to access the hash elements and the [] to access the array elements, and that you can concatenate them as you like for whatever structure you have.

    True laziness is hard work
      I absolutely agree with you that this is a horrible way to get the structure.

      The original problem was getting the recent changes from a mediawiki site. I use the excellent mod:MediaWiki::Bot module to retrieve the info using the Mediawiki API.

      What you get is then an array of hashes with this structure:

      $VAR50 = { 'revid' => 174, 'ns' => 0, 'comment' => '', 'timestamp' => '2013-04-01T12:30:28Z', 'user' => 'user', 'title' => 'page title', 'type' => 'edit', 'pageid' => 50, 'old_revid' => 173, 'rcid' => 180 };
      But I then need to put it all together per user: pages edited, number of edits, etc. It would be much easier if I had database access but that is a no-no Thanks for taking the time to look into this.

        Have you looked at DBD::SQLite? It's completely stand alone - just install the module and you've got the whole thing. Maybe the advice in Yes, even you can use CPAN may help too?

        True laziness is hard work
Re: dereference array
by hdb (Monsignor) on Dec 03, 2013 at 13:21 UTC

    @edits is an array not a reference to an array. No need to dereference it. Each element of @edits is a reference to an array with a single element. The following should work:

    print join('|', map {$_->[0]} @edits), "\n";

    Update: changed parentheses. Thanks Athanasius.

Re: dereference array
by hippo (Bishop) on Dec 03, 2013 at 13:19 UTC

    You don't have a reference to an array, you have a real array, so there's no need to dereference anything. eg.

    print join('|', @edits), "\n";
      Thanks for your (very fast) reply!

      I have indeed an array ... of arrays:

      ARRAY(0x235bc88)|ARRAY(0x235bd18)|ARRAY(0x235bd90)|ARRAY(0x235be08)|ARRAY...

      Ok, a step in the right direction.

        Apologies, I missed that. When you call Dumper with an array argument it displays each element as a different VAR which misled me.

        So actually, you have an array, each member of which is an arrayref. This means you hook into the outer array directly but into the elements as references, so the print statement could become something like:

        print join('|', map { $_->[0] } @edits), "\n";

        In map the $_ is a placeholder for each element of the @edits array, which we then use to extract element zero to be passed to join.

        HTH.

        PS. I'm not convinced there's much value in using this data structure to begin with, unless you will make the arrayrefs multi-valued at some point. You could again use map to change this:

        @edits = map { $_->[0] } @edits; # Now @edits is just an array of scalars so we can print join('|', @edits), "\n";

        Just a thought.

      Dumper is printing each element of the array, which is an array reference ...

      use strict; use warnings FATAL => 'all'; use Data::Dumper; my @p = ( 0 .. 1 ); my @q = map [ $_ ] , @p; print Dumper @p; print "\n"; print Dumper @q; print "\n";