Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

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

Replies are listed 'Best First'.
Re: push foreach glob - bug?
by ikegami (Patriarch) 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 ]
Re: push foreach glob - bug?
by shmem (Chancellor) 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 ;-)

Log In?

What's my password?
Create A New User
Domain Nodelet?
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 imbibing at the Monastery: (2)
As of 2022-09-24 18:33 GMT
Find Nodes?
    Voting Booth?
    I prefer my indexes to start at:

    Results (115 votes). Check out past polls.