Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid

push foreach glob - bug?

by sfink (Deacon)
on Jan 13, 2010 at 22:37 UTC ( #817298=perlquestion: print w/ replies, xml ) Need Help??
sfink has asked for the wisdom of the Perl Monks concerning the following question:

I'm trying to separate a list of MP3 files into two groups: the ones matching /ad/ and the rest.

I am puzzled why this works:

perl -le 'push @{$f[/ad/]}, $_ foreach glob("*.mp3"); use Data::Dumper +; print Dumper(\@f)'
while this does not:
perl -le '@f = glob("*.mp3"); push @{$f[/ad/]}, $_ foreach @f; use Dat +a::Dumper; print Dumper(\@f)'
The latter puts everything into $f[0], matching or not.
This is perl, v5.10.0 built for i386-linux-thread-multi

Comment on push foreach glob - bug?
Select or Download Code
Re: push foreach glob - bug?
by shmem (Canon) on Jan 13, 2010 at 22:54 UTC

    Hm. Modifying an array whilst iterating over it? Maybe you should rather say

    perl -le '@l = glob("*.mp3"); push @{$f[/ad/]}, $_ foreach @l;

    (update) since @l[0,1] contain file names, not array references.

      Modifying elements of an array over which one is iterating doesn't cause problems. It's done all the time:
      s/^\s+//, s/\s+$// for @array;

        Right. But modifying values that way doesn't involve coercion of a string into an array reference... (I have just been giving a hint to puzzle further ;-)

Re: push foreach glob - bug?
by ikegami (Pope) on Jan 13, 2010 at 22:56 UTC

    When you have a problem, don't hide the errors! Use use strict; and use warnings;.

    $ perl -Mstrict -wle'my @f = glob("*.mp3"); push @{$f[/ad/]}, $_ forea +ch @f;' Can't use string ("bar.mp3") as an ARRAY ref while "strict refs" in us +e at -e line 1.

    In the first snippet, $f[0] and $f[1] contain undef or an array reference. push @{$f[...]}, pushes unto the referenced array (creating it if necessary).

    In the second snippet, $f[0] and $f[1] contain file names. push @{$f[...]}, uses the file name as an array name and push unto the named array.

    $ perl -le '@f = glob("*.mp3"); push @{$f[/ad/]}, $_ foreach @f; use D +ata::Dumper; print Dumper(\@f, \@{"bad.mp3"}, \@{"bar.mp3"})' $VAR1 = [ 'bad.mp3', 'bar.mp3', 'foo.mp3', 'moo.mp3' ]; $VAR2 = [ 'bar.mp3', 'foo.mp3', 'moo.mp3' ]; $VAR3 = [ 'bad.mp3' ];

    Perhaps you shouldn't use the same array to save your file names and your arrays of file names...

      Doh! I'm an idiot. Thanks. I had turned on warnings, but not strict. Surprisingly, warnings showed nothing -- I was expecting to get something from using the return value of /ad/ as an array index when /ad/ failed to match.

      But yes, I somehow completely missed the fact that I was using the same array for both purposes. I think my subconscious was thinking that because I was using array refs, I was using $f not @f. Stupid subconscious.

      Another case of being blinded by thinking it was too simple for such an obvious problem to hide...

        I was expecting to get something from using the return value of /ad/ as an array index

        You got lucky.

        On failure, when called in scalar context, it happens to return a value that's both the number zero and the empty string.

        On success, when called in scalar context, it happens to return 1.

        Both results are undocumented and unreliable. You're only guaranteed to get a true or false value.

        $f[ /.../ ]
        should be
        $f[ /.../ ? 1 : 0 ]

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://817298]
Approved by broomduster
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (15)
As of 2014-07-11 18:36 GMT
Find Nodes?
    Voting Booth?

    When choosing user names for websites, I prefer to use:

    Results (235 votes), past polls