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

Here is the context of the problem. Suppose our environment has several DNS subdomains of the pattern "area01", "area02", "area03". Withing each subdomain, the hosts names are repeated: "peanut", "cashew", "almond", "hazel".

My perl script will be doing something with these hostnames, and I want to give the user a shorthand for inputting the host name on the command line. One can run the command like this.

./myscript.pl -h peanut 01 13 44 18 27

This will target the hosts peanut.area01, peanut.area13, and so forth.

Here is the test example of how I'm doing this.

#!/usr/bin/perl -w use warnings; use strict; # Will be set by getopt(). my %opt = ( 'h' => 'peanut,cashew'); # Contains only shorthand subdomains for now, but items will be # expanded to full hostnames. my @hosts = ( '01', '13', '09'); # The short hostnames to target in each subdomain. my @shorts = (split /,|\s+/, $opt{'h'}); for my $h (@hosts) { if ($h =~ m/^(\d{2})$/) { for my $short (@shorts) { push @hosts, "$short.area$h"; } } } @hosts = grep {!/^\d{2}$/} @hosts; print join(' ', @hosts) . "\n";

What I am wondering is there a map (maybe splice?) syntax that will accomplish this?

I am familiar (as of today) with tye's Filter function in Algorithm::Loops, and, in fact, reading the Motivation section is greatly educational. However, I would rather not use a module as I want to gain a greater mastery with the core functions at this time. Regardless, if you have a helpful module in mind, please list it for the benefit of others with a similar problem who may be reading this node.

  • Comment on Can map or splice replace my use of for loop + push + grep for my array transmogrification?
  • Select or Download Code

Replies are listed 'Best First'.
Re: Can map or splice replace my use of for loop + push + grep for my array transmogrification?
by ikegami (Patriarch) on Nov 04, 2009 at 00:16 UTC

    It has just occurred to me that the digit check might only be there because you were using a buggy for loop. If so, the solutions are much simpler.

    for:

    my @fulls; for my $area (@areas) { for my $short (@shorts) { push @fulls, "$short.area$area"; } }

    map:

    my @fulls = map { my $area = $_; map "$_.area$area", @shorts } @areas;

    More intuitive map, but different order produced:

    my @fulls = map { my $short = $_; map "$short.area$_", @areas } @shorts;

    NestedLoops:

    use Algorithm::Loops qw( NestedLoops ); my @fulls = NestedLoops( [ \@areas, \@shorts ], sub { "$_[1].area$_[0]" }, );

      Doh! You're right. Sorry about that. In simplifying and sanitizing my example for posting, the digit check no longer makes sense, does it?

      I must do the digit check because that is just one form of shorthand that I'm allowing. The other forms don't match that pattern.

Re: Can map or splice replace my use of for loop + push + grep for my array transmogrification?
by ikegami (Patriarch) on Nov 03, 2009 at 23:48 UTC

    First of all, don't modify the array over which for iterates.

    If any part of LIST is an array, foreach will get very confused if you add or remove elements within the loop body

    Fixed:

    my @temp; for my $h (@hosts) { if ($h =~ m/^\d{2}\z/) { for my $short (@shorts) { push @temp, "$short.area$h"; } } else { push @temp, $h; } } @hosts = @temp;

    The inner for loop can be replaced with map simply:

    my @temp; for my $h (@hosts) { if ($h =~ m/^\d{2}\z/) { push @temp, map "$_.area$h", @shorts; } else { push @temp, $h; } } @hosts = @temp;

    You can also replace the exterior for loop with map too:

    @hosts = map { if (/^\d{2}\z/) { my $h = $_; map "$_.area$h", @shorts } else { $_ } } @hosts

    The above could be golfed, but I fear readability will suffer.

    Filter isn't useful here since it only handles 1-to-1 transformations.

      Thanks much. I'm very appreciative. I'm just pointing out a wee typo, tho. You skipped a $.

      push @temp, map "$_.area$h", @shorts;

      ...unless you did that intentionally as some sort of test.

        unless you did that intentionally

        No, fixed.