Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

map weirdness

by insaniac (Friar)
on Dec 13, 2004 at 12:40 UTC ( [id://414358]=perlquestion: print w/replies, xml ) Need Help??

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

hey guys,
I'm playing with the map sub, I just recently discovered all the need tricks you can do with.
but since i'm posting here, i must be stuck at some point.
please have a look at the following:
perl -e '@d=([0,"BE"],[3,"BUS"],[4,"BUS2"]); @a=map($_ , split(/,/, "B +US2,BE") ) ; @b=map { my $mapkey=$_; map { [@{$d[$mapkey]}] if $d[$ma +pkey]->[1] =~ /$a[$_]/ } 0..$#a } 0..$#d; use Data::Dumper;print Dump +er(@b);' $VAR1 = ''; $VAR2 = [ 0, 'BE' ]; $VAR3 = ''; $VAR4 = ''; $VAR5 = [ 4, 'BUS2' ]; $VAR6 = '';

or more readable:
my @d=([0,"BE"],[3,"BUS"],[4,"BUS2"]); # some default values my @a=map($_ , split(/,/, "BUS2,BE") ) ; # a customer setting for + instance my @b=map { my $mapkey=$_; map { [@{$d[$mapkey]}] if $d[$mapkey]->[1] =~ /$a[$_]/ } 0..$#a } 0..$#d; # @b will contain stuff that nee +ds to be configured use Data::Dumper; print Dumper(@b);' __END__ gives the following output: $VAR1 = ''; $VAR2 = [ 0, 'BE' ]; $VAR3 = ''; $VAR4 = ''; $VAR5 = [ 4, 'BUS2' ]; $VAR6 = '';
The above code is a test scenario ofcourse.
What I want to achieve is that @b contains only the anonymous arrays which are found in @d, so i don't want the undef entries.
Any help is greatly appreciated...
Cheers!
--
to ask a question is a moment of shame
to remain ignorant is a lifelong shame

Replies are listed 'Best First'.
Re: map weirdness
by ysth (Canon) on Dec 13, 2004 at 12:49 UTC
    I'm guessing you need to change this part:
    [@{$d[$mapkey]}] if $d[$mapkey]->[1] =~ /$a[$_]/
    That generates an undef when the match fails, and shallow-copies the arrayref $d[$mapkey] when the match succeeds. Sounds like you want something more like (untested):
    $d[$mapkey]->[1] =~ /$a[$_]/ ? [@{$d[$mapkey]}] : ()
    to provide an empty list when the match fails. Using ?: in a map is a common idiom.
      thanx dude!!!
      /me hides in shame again... i could have come up with this myself :-$
      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame
Re: map weirdness
by jonadab (Parson) on Dec 13, 2004 at 13:00 UTC
    What I want to achieve is that @b contains only the anonymous arrays which are found in @d, so i don't want the undef entries.

    I can think of two major ways to obtain that result. One way would be if you leave map like it is but then use grep to filter out the undesired results:

    @b = grep { ref $_ } @b;

    The other way would be to change the map so that it only returns what you want in the first place, something along these lines...

    my @b=map { my $mapkey=$_; map { ($d[$mapkey]->[1] =~ /$a[$_]/) ? [@{$d[$mapkey]}] : () } 0..$#a } 0..$#d;

    (This code is all untested.)

    The first approach is probably easier to follow, if you're new to Perl. The second approach is more direct, however, probably more efficient, and definitely more concise.

    Of course, if I were writing the thing, I'd get rid of those array indices and map over the lists themselves...

    my @b = map { my $d = $_; map { ($d->[1] =~ $$_) ? $d : () } @a } @d

    And if by =~ you really mean eq, we can simplify this further using a hash:

    my %a = map { $_ => 1 } @a; my @b = map { ($a{$_->[1]}) ? $_ : () } @d
    Update: fixed a variable there.

    Note that this last one doesn't do exactly the same thing. With your sample data set it gets the same result, and I *suspect* that it actually does what you want, but now if @a were to contain "BUS", @d would no longer get [4,"BUS2"], only [3,"BUS"]. But it exorcises the nested map, which makes it easier to follow and more efficient, if it does what you want.


    "In adjectives, with the addition of inflectional endings, a changeable long vowel (Qamets or Tsere) in an open, propretonic syllable will reduce to Vocal Shewa. This type of change occurs when the open, pretonic syllable of the masculine singular adjective becomes propretonic with the addition of inflectional endings."  — Pratico & Van Pelt, BBHG, p68

      Excellent post, but I feel like I need to write in defense of the "first approach." Not only is it "easier to follow, if you're new to Perl," but I think it's easier to follow even if you're not new to Perl. In other words, it's simply clearer code.

      I say this because map and grep have fairly common, specific uses. Nearly anyone reading the code will immediately recognize grep as filtering the results. Shoving that logic into the map block fails to take advantage of that quick recognition. It may not seem like a lot, but these things add up.

        I feel like I need to write in defense of the "first approach." Not only is it "easier to follow, if you're new to Perl," but I think it's easier to follow even if you're not new to Perl.

        Up to a point, I'd agree. Indeed, there's a reason I gave both approaches. Yet, you'll notice that it was when I went to the second approach that I felt the need to simplify the map (getting rid of the array indices -- this is Perl, not C), and then only after I'd done that did I really understand the logic of what was going on well enough to construct my fourth solution, which removes the nested map altogether. Having done that, we could combine it with the grep approach...

        my %a = map { $_ => 1 } @a; my @b = grep { $a{$_->[1]} } @d

        This is perhaps clearest of all, if it does the right thing, which I suspect it does. I find it hard to believe that the original poster actually wanted the side-effect of matching substrings in this case.


        "In adjectives, with the addition of inflectional endings, a changeable long vowel (Qamets or Tsere) in an open, propretonic syllable will reduce to Vocal Shewa. This type of change occurs when the open, pretonic syllable of the masculine singular adjective becomes propretonic with the addition of inflectional endings."  — Pratico & Van Pelt, BBHG, p68
Re: map weirdness
by zejames (Hermit) on Dec 13, 2004 at 13:09 UTC
    By the way, you are using
    [@{$d[$mapkey]}]

    which means that you have a array ref, $d{$mapkey} that you derefence through @{$d[$mapkey]}, and then you want to have the corresponding array ref. This is not useful, just use :

    $d[$mapkey]

    HTH


    --
    zejames
      Those aren't the same; try:
      $, = " "; $d[3] = [qw/just another perl hacker/]; $copy1 = $d[3]; $copy2 = [@{$d[3]}]; print "\$d[3] was", @{$d[3]}, "\n"; $d[3][2] =~ y/p/P/; print "\$d[3] now", @{$d[3]}, "\n"; print "\$copy1 is", @$copy1, "\n"; print "\$copy2 is", @$copy2, "\n"; __END__ $d[3] was just another perl hacker $d[3] now just another Perl hacker $copy1 is just another Perl hacker $copy2 is just another perl hacker
      The [@{}] syntax copies the array elements into a new array, without it, you are sharing the same array.
        well, it works in my case..
        insaniac][amano: ~ : perl -we 'use strict;my @d=([0,"BE"],[3,"BUS"],[4 +,"BUS2"]);my @a=map($_ , split(/,/, "BUS2,BE") ) ; my @b=map { my $ma +pkey=$_; map { $d[$mapkey]->[1] =~ /$a[$_]/ ? $d[$mapkey] : () } 0..$ +#a } 0..$#d; use Data::Dumper;print Dumper(@b);' $VAR1 = [ 0, 'BE' ]; $VAR2 = [ 4, 'BUS2' ]; insaniac][amano: ~ : perl -we 'use strict;my @d=([0,"BE"],[3,"BUS"],[4 +,"BUS2"]);my @a=map($_ , split(/,/, "BUS2,BE") ) ; my @b=map { my $ma +pkey=$_; map { $d[$mapkey]->[1] =~ /$a[$_]/ ? [@{$d[$mapkey]}] : () } + 0..$#a } 0..$#d; use Data::Dumper;print Dumper(@b);' $VAR1 = [ 0, 'BE' ]; $VAR2 = [ 4, 'BUS2' ];
        --
        to ask a question is a moment of shame
        to remain ignorant is a lifelong shame

      That's not necessarily true. Doing this creates a new arrayref with the same contents, but if down the line he's manipulating the map'd contents but wants to be able to run more results through the same process he may very well want to have copied the original data (since if he alters the map'd contents down the line it'll affect what he's using to build the new list). It is more inefficient than just using the arrayref, but depending on what he's trying to do it might be correct.

      do more with less... i like, thanx dude! (again /me crawls away with his head as red as a tomato)
      --
      to ask a question is a moment of shame
      to remain ignorant is a lifelong shame
        again /me crawls away with his head as red as a tomato

        Nothing to be ashamed of. You're learning. We all have to do that.

      Actually, [@{$d[$mapkey]}] and $d[$mapkey] are not the same. The first makes a copy, the second doesn't.
      #!/usr/bin/perl use strict; use warnings; my @d = ([0, 1, 2], [3, 4, 5], [6, 7, 8]); my $mapkey = 1; sub show { local($") = ", "; print("[", join(", ", map({"[@$_]"} @d)), "]\n"); } my $one = [@{$d[$mapkey]}]; my $two = $d[$mapkey]; show; # Show array. Unmodified. $one->[1] = "foo"; show; # Array is still unmodified. $two->[1] = "foo"; show; # This modifies the array. __END__ [[0, 1, 2], [3, 4, 5], [6, 7, 8]] [[0, 1, 2], [3, 4, 5], [6, 7, 8]] [[0, 1, 2], [3, foo, 5], [6, 7, 8]]
Re: map weirdness
by Animator (Hermit) on Dec 13, 2004 at 16:34 UTC
    Any particular reason you use: my @a=map($_ , split(/,/, "BUS2,BE") ) ;and not my @a = split /,/, "BUS2,BE";?

    (Update: typo)

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (8)
As of 2024-03-28 10:10 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found