in reply to A Not so Simple Append

You mean like this?

#!/usr/bin/perl -w use strict; my %seen = (); while (<DATA>) { my ($one, $two) = split; $seen{$one} = [$two, exists $seen{$one} ? @{$seen{$one}} : () ]; } for my $key (keys %seen) { print $key, " ", join(", ", @{$seen{$key}}), "\n"; } __DATA__ a 1 a 2 a 3 a 4 b 1 c 1 d 1

Christian Lemburg
Brainbench MVP for Perl
http://www.brainbench.com

Replies are listed 'Best First'.
RE: Re: A Not so Simple Append
by merlyn (Sage) on Oct 03, 2000 at 04:14 UTC
    while (<DATA>) { my ($one, $two) = split; $seen{$one} = [$two, exists $seen{$one} ? @{$seen{$one}} : () +]; }
    You should rely on autovivification rather than recreating the array each time. For example, the easy form of what you wrote is:
    while (<DATA>) { my ($one, $two) = split; push @{$seen{$one}}, $two; }
    If you insist on having the new elements at the beginning, change push to unshift, slightly less efficient.

    -- Randal L. Schwartz, Perl hacker

      Conceptually push and unshift are exactly symmetrical, along with pop and shift. Is there really a performance difference?

      I tried it and wow:

      use strict; use Benchmark; use vars qw(%test); %test = ( push => sub { my @tmp; push @tmp, "bar" foreach 1..10000; }, unshift => sub { my @tmp; unshift @tmp, "bar" foreach 1..10000; }, ); timethese (-5, \%test); __END__ Benchmark: running push, unshift, each for at least 5 CPU seconds... push: 5 wallclock secs ( 5.46 usr + 0.05 sys = 5.51 CPU) @ 17 +.42/s (n=96) unshift: 8 wallclock secs ( 8.08 usr + 0.11 sys = 8.19 CPU) @ 0 +.73/s (n=6)
      Why is the one so much faster than the other?

        benefits of the array structure... you just make a new scalar and add a pointer to the end of the array with push. With unshift, you make a scalar, copy every pointer in the array over one, and stick the new pointer at the beginning.

        PerlGuts Illustrated may help you see that. See Arrays.

        --
        $you = new YOU;
        honk() if $you->love(perl)

      Thanks for pointing this out! I did not know that this is possible - all the documentation about autovivification mentions it in the context of "chain" dereferencing, so I thought (or rather, "feeled") that it was connected to this operation exclusively. Is there any statement in the docs or the source somewhere that defines when autovivification will happen?

      Christian Lemburg
      Brainbench MVP for Perl
      http://www.brainbench.com

        It's pretty simple. I don't know how it's documented, since I learned it mostly by folklore (and by watching the response to bug reports on P5P {grin}).

        When a variable containing undef (or a new element of an array or hash) is used in an "lvalue-context" (on the left side of an assignment, for example) as a reference, a reference to the appropriate anonymous thingy is inserted and the operation continued, rather than throwing an error for an attempt to dereference undef.

        So, push @$x, 35 works even if $x is undef, because we're about to dereference $x while trying to store something.

        It's really just an extension of the principle that

        $last_name{"fred"} = "flintstone";
        works, even though I didn't originally create the element with that key.

        -- Randal L. Schwartz, Perl hacker

        merlyn and I disagree on whether it is documented.

        Look at perlref, item 6 on how to create a reference is to dereference them in a context that assumes they exist. That is why chained lookups autovivify, to continue down the chain the previous lookups were dereferenced in a context that assumed they existed. Likewise if you start assigning to stuff, it autovivifies. That holds for hashes and variables.

        Now merlyn certainly knows this piece of documentation, so why do we disagree on whether it is documented? Well to his eyes this requires serious "reading between the lines" and you cannot expect people to figure it out. To mine, well the reader's attention is not drawn to the point, but once I saw that this is the rule that applies, I have not since run into an autovivification situation which I had trouble understanding...