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

how to avoid using index of array

by Achilles_Sea (Novice)
on Nov 13, 2011 at 04:44 UTC ( [id://937793]=perlquestion: print w/replies, xml ) Need Help??

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

Hi Monks,

I have 2 arrays. The guys in @rray1 are going to marry girls in @rray2 by the right order.
However, I want to use only 1 foreach, or some method without index of array as there is a saying A real perl programmer seldom users indexes, but how?

my @rray1 = qw/boy boymonkey boydog/; my @rray2 = qw/girl girlmonkey girldog/; foreach ...(){ //marriage($rray1[i], $rray2[i]); }

Replies are listed 'Best First'.
Re: how to avoid using index of array
by AnomalousMonk (Archbishop) on Nov 13, 2011 at 05:03 UTC

    Maybe the point your teacher is trying to make is to investigate some of the Fine Modules on CPAN. E.g.:

    >perl -wMstrict -le "my @rray1 = qw/boy boymonkey boydog/; my @rray2 = qw/girl girlmonkey girldog/; ;; use List::MoreUtils qw(pairwise); use vars qw($a $b); my @unions = pairwise { [ $a, $b ] } @rray1, @rray2; ;; use Data::Dumper; print Dumper \@unions; " $VAR1 = [ [ 'boy', 'girl' ], [ 'boymonkey', 'girlmonkey' ], [ 'boydog', 'girldog' ] ];

    Update: Although if you're supposed to do it with a single for-loop and no indexing, maybe your teacher has something like this in mind (but this destroys the  @gals array):

    >perl -wMstrict -le "my @guys = qw/boy boymonkey boydog/; my @gals = qw/girl girlmonkey girldog/; ;; my @unions; for my $guy (@guys) { push @unions, [ $guy, shift @gals ]; } ;; use Data::Dumper; print Dumper \@unions; " $VAR1 = [ [ 'boy', 'girl' ], [ 'boymonkey', 'girlmonkey' ], [ 'boydog', 'girldog' ] ];
Re: how to avoid using index of array
by moritz (Cardinal) on Nov 13, 2011 at 07:43 UTC

    No problem if you're not constrained in what Perl version you can use:

    use v6; my @male = qw/boy boymonkey boydog/; my @female = qw/girl girlmonkey girldog/; for @male Z @female -> $m, $f { say "$m marries $f"; }

    (Works fine in niecza and rakudo).

      I knew that it would be (and glad that it was) just a matter of time before you posted a Perl6 and zip operator solution.

      I've been trying to figure out how to do that (before you made your post) using Perl 6 and the zip operator. Thanks for posting an example. For some reason I was expecting that the syntax should look more like this:

      for( @male Z @female )->[$m,$f] { # .... }

      But apparently not. ;) Also, how would you push a stringified concatenation onto a new array? In Perl5 either of these would do WIM:

      my @married; foreach( 0 .. $#male ) { push @married, "$male[$_] $female[$_]"; } # OR ..... my @married = map { "$male[$_] $female[$_]" } 0 .. $#male; # OR with List::MoreUtils::pairwise my @married = pairwise{ "$a $b" } @male, @female;

      ...or you could forgo interpolation and use the (.) dot operator.

      I've been puzzling over a Perl6-ish, Zip-operator-ish way to do the same.


      Dave

        For some reason I was expecting that the syntax should look more like this:
        for( @male Z @female )->[$m,$f] { # .... }

        Close. Two things got into your way. The first is syntactic: you need a space between for and (. The reason is that (nearly) everything of the form identifier(...) is parsed as a subroutine call. That way keywords don't conflict with function names, making it more robust to introduce new syntax.

        The second one is a bit more interesting. In a signature, [$m, $f] stands for a single parameter, which is taken as a list, and unpacked into the two variables. But @list1 Z @list2 returns a list of lists which flattens the sublists when you iterate over it. To stop that flattening, you can write

        for (@male Z @female).tree ->[$m,$f] { # .... }

        which indeed works in current Rakudo.

        Also, how would you push a stringified concatenation onto a new array?

        Several ways:

        my @array; for @male Z @female -> $m, $f { push @array, "$m $f; # or @array.push: "$m $f"; # or @array.push: $m ~ ' ' ~ $f } # or my @array = (@male Z @female).map("$^a $^b");

        Since Z can also be used as a meta operator, you can also get zip and concatenation in one go, using Z~:

        my @array = @male Z~ @female; # without joining space

        To get the space between the two operands, you can use one of these tricks:

        # with the list repetition operator: @array = @male Z~ ' ' xx @male Z~ @female; # with cross instead of zip: @array = @male X~ ' ' Z~ @female;

        All of these solutions work with current Rakudo.

Re: how to avoid using index of array
by davido (Cardinal) on Nov 13, 2011 at 05:16 UTC

    You didn't mention what you want marriage() to do, but it probably doesn't really matter. Here's an example of how you can do it without indices, using List::MoreUtils pairwise function.

    It looks a lot like map, except that it takes two arrays, not one, and it aliases each pair of elements as $a and $b instead of $_. Its prototype requires that you pass it two arrays, whereas map is happy to receive a list not specifically held in an array.

    Here's some example code where we've set up marriage() to just 'join' the elements together with a single space character binding them. You could easily modify it to return an arrayref, or even do away with it entirely and do all your work inside the pairwise{...} block.

    use strict; use warnings; use List::MoreUtils qw/pairwise/; my @rray1 = qw/ boy boymonkey boydog /; my @rray2 = qw/ girl girlmonkey girldog /; our( $a, $b ); my @married = pairwise{ marriage( $a, $b ) } @rray1, @rray2; print "$_\n" for @married; sub marriage { return join ' ', @_; }

    The output will be:

    boy girl boymonkey girlmonkey boydog girldog

    If you have warnings enabled, it's necessary to either say "our( $a, $b );", or no warnings qw/once/; (within the smallest scope possible scope, such as inside of the pairwise{...} block), or some other means of satisfying the "used only once" warning for $a and $b.

    While pairwise{} is a convenience, I really don't see any big advantage over this:

    my @married = map{ marriage( $rray1[$_], $rray2[$_] ) } 0 .. $#rray1;

    That snippet does iterate over the index which some nut may say is bad form, but on the other hand, it eliminates the need to pull in a CPAN module just for one line of sugar. The map{} approach even eliminates the need to worry about the "used only once" warning.


    Dave

Re: how to avoid using index of array
by clueless newbie (Curate) on Nov 13, 2011 at 13:55 UTC
    Use a hash?
    use strict; use warnings; my @guys=qw(Tom Dick Harry); my @gals=qw(Jane Mary Pamela); # The real work ... my %marriages; @marriages{@guys}=@gals; for my $guy (keys %marriages) { print "$guy - $marriages{$guy}\n"; }
    prints
    Dick - Mary Harry - Pamela Tom - Jane

      Didn't you ever do first grade? Dick is with Jane and their baby is Spot.

      As Occam said: Entia non sunt multiplicanda praeter necessitatem.

        Now we know what D in TomDLux stands for :)
Re: how to avoid using index of array
by Plankton (Vicar) on Nov 13, 2011 at 06:34 UTC
    Stacks?
    plankton@chumbucket:~$ cat stack.pl #!/usr/bin/perl -w use strict; my @boys = qw/boy boymonkey boydog/; my @girls = qw/girl girlmonkey girldog/; while (@boys){ # will be boys my $boy = pop( @boys ); my $girl = pop( @girls ); print "boy =[$boy] girl=[$girl]\n"; } plankton@chumbucket:~$ ./stack.pl boy =[boydog] girl=[girldog] boy =[boymonkey] girl=[girlmonkey] boy =[boy] girl=[girl]
Re: how to avoid using index of array
by Anonymous Monk on Nov 13, 2011 at 04:47 UTC

    However, I want to use only 1 foreach, or some method without index of array as there is a saying A real perl programmer seldom users indexes, but how?

    yes, idiots say a lot of things

    use an index

      Oh snap, I used an index
      my @rray1 = qw/boy boymonkey boydog/; my @rray2 = qw/girl girlmonkey girldog/; while( my ( $i, $v ) = each @rray1 ){ print " $v => $rray2[$i]\n"; } __END__ boy => girl boymonkey => girlmonkey boydog => girldog

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://937793]
Approved by davido
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (3)
As of 2024-04-24 23:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found