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

Hello all,
I needed to interleave two arrays and found the following suggestion on perlmonks.com:
@foo = ( 1 , 3 , 5 , 7 ); @bar = ( 2 , 4 , 6 , 8 ); @baz = map { ( $_ , shift @bar ) } @foo;
I applied the following code in my script:
print STDOUT my @foobar = map { ( $_, shift @foo ) } @bar;
and it worked, but when I turn on use warnings; I get the following error:
Use of uninitialized value in print at line 3
I've done some research and it seems that some people just complain about using warnings and turn them off (I don't want to do that), and other say to re-work the code into a while loop. Anyone have any advice as to how I can keep the code while getting rid of the error?

Replies are listed 'Best First'.
Re: Uninitialized Value Error When Interleaving
by arturo (Vicar) on Jul 02, 2001 at 21:39 UTC

    Running that code with the second line alone works fine for me (Perl 5.6.1).

    I suspect that your problem is that the use of shift in the map *destructively* processes the @foo array -- shift pulls the first element of the array out of @foo, so when you go to do the shift trick again, you're processing an empty array. You can see this if you add the following code after the first 'interleave':

    my $foo_size = @foo; print "\nThere are now $foo_size elements in \@foo\n";

    In this case, warnings told you about something very important!

    perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
Re: Uninitialized Value Error When Interleaving
by clintp (Curate) on Jul 02, 2001 at 21:37 UTC
    First, that's a really, really ugly place for the my declaration. It's carrying things just a bit too far. Move it somewhere else.

    Secondly, running your sample produces no warnings for me. It probably shouldn't. However if @foo and @bar don't have the same number of elements (specifically, if @foo is short) then you'll get enough undef values in the array to make up the difference.

    Thirdly, did you really mean to print and do the assignment at the same time? Yeah, you'll get the return value from the assignment printed, but is that really what you wanted? (Tends to be ugly, that's all).

      1) I will move the my declaration.
      2) Yes @foo is shorter. My code should have read...
      #!/usr/bin/perl use warnings; use strict; my @foo = ( 1 , 3 , 5 , 7 ); my @bar = (0, 2 , 4 , 6 , 8 ); print STDOUT my @foobar = map { $_, shift @foo } @bar;
      I'm assuming that this is my problem, no? I do get the proper result "012345678"...just with a warning.
      3) I guess I have a talent for ugly... and warnings :-(
        As for #2...no you don't get the proper results. What you're actually getting is: 012345678undef but of course undef doesn't print. :)

        Watch this. It's your code with two small modifications:

        use warnings; use strict; my @foo = ( 1 , 3 , 5 , 7 ); my @bar = (0, 2 , 4 , 6 , 8 ); my @foobar= map { $_, shift @foo } @bar; print STDOUT join(',', @foobar);
        When you run this, notice that the list is going to have a trailing ",". That's because join() knows there's an element after the 8 (undef!) and makes a slot for it. And notice the error changed, its now an uninit value in join.
Re: Uninitialized Value Error When Interleaving
by bikeNomad (Priest) on Jul 02, 2001 at 21:36 UTC
    I don't know why you're getting the warning; I don't with this script:

    #!/usr/bin/perl -w use strict; my @foo = ( 1 , 3 , 5 , 7 ); my @bar = ( 2 , 4 , 6 , 8 ); print STDOUT my @foobar = map { $_, shift @foo } @bar;
    Unless, that is, you left the @baz line in. Note that you are destroying @foo in the process (by calling shift); if you do it more than once, you'll have an empty array the second time.
      what if you try this:
      #!/usr/bin/perl use warnings; use strict; my @foo = ( 1 , 3 , 5 , 7 ); my @bar = ( 2 , 4 , 6 , 8 ); print STDOUT my @foobar = map { $_, shift @foo } @bar;
        Um, that's exactly what I had (that is, "perl -w" is the same as "use warnings"). But as I and others have said, it's not usually a great idiom, as it's destructive to @foo. And you'll still have undefined values if @foo is shorter than @bar.
(tye)Re: Uninitialized Value Error When Interleaving
by tye (Sage) on Jul 02, 2001 at 22:03 UTC

    You should probably avoid destroying @foo during the merge: my @foobar= map { ($bar[$_],$foo[$_]) } 0..$#bar; or

    use mapcar; my @foobar= mapcar { @_ } \@bar, \@foo;
    See mapcar.

            - tye (but my friends call me "Tye")
Re: Uninitialized Value Error When Interleaving
by CharlesClarkson (Curate) on Jul 02, 2001 at 21:54 UTC

    The only way I could produce the error was if @foo was a shorter array than @bar.

    @foo = ( 1 , 3 , 5 , 7 ); @bar = ( 2 , 4 , 6 , 8 , 9); print STDOUT my @foobar = map { ( $_, shift @foo ) } @bar;

    Unfortunately, I don't know what you want to do if they are not the same size. So I'll guess:

    @foo = ( 2 , 4 , 6 , 8 ); @bar = ( 1 , 3 , 5 , 7, 9); $len = @foo; print STDOUT my @foobar = ( (map { ( $_, shift @foo ) } @bar[0 .. $len - 1]), @bar[$len .. $#bar] );

    HTH,
    Charles K. Clarkson