http://qs1969.pair.com?node_id=950920

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

Hi all,

I'm trying to see which is easier for maint. I have the following and wondering if I should replace it with map and grep. Not sure why, but find myself not reaching for them ever. This turns letters on your phone dialpad to numbers:

use strict; use warnings; use 5.10.1; my $filter_clean = 'GAV18'; my %filter_map = ( A => 2, B => 2, C => 2, D => 3, E => 3, F => 3, G => 4, H => 4, I => 4, J => 5, K => 5, L => 5, M => 6, N => 6, O => 6, P => 7, Q => 7, R => 7, S => 7, T => 8, U => 8, V => 8, W => 9, X => 9, Y => 9, Z => 9, ); # 1st version my $filter = q{}; if ($filter_clean) { my @filter_split = split //, $filter_clean; for my $fc (@filter_split) { if ( $fc =~ /\d/ ) { $filter .= $fc; } else { $filter .= $filter_map{ uc $fc }; } } } say $filter; # 2nd version. Why would I use below (when it's working right, that is +) over above? $filter .= map { $filter_map{ uc $_ } } grep { !/\d/ and $filter_clean } split//, $filter_clean; say $filter; [ghenry@linux]$ perl t/map.pl 42818 428183

I also need to make this work properly so I'm not returning the amount of matches grep has.

Advice? I prefer my first version for when I come back later.

Walking the road to enlightenment... I found a penguin and a camel on the way.....
Fancy a yourname@perl.me.uk? Just ask!!!

Replies are listed 'Best First'.
Re: map and grep or clear code?
by ikegami (Patriarch) on Jan 31, 2012 at 10:13 UTC

    Your code:

    my %filter_map = ( ... ); my $filter = q{}; if ($filter_clean) { my @filter_split = split //, $filter_clean; for my $fc (@filter_split) { if ( $fc =~ /\d/ ) { $filter .= $fc; } else { $filter .= $filter_map{ uc $fc }; } } } say $filter;

    Simpler procedural code:

    my %map = ( ... ); $map{$_} = $_ for 0..9; my $numeric; for (split //, uc($word)) { $numeric .= $map{$_}; } say $numeric;

    Simpler functional code:

    my %map = ( ... ); $map{$_} = $_ for 0..9; my $numeric = join '', map $map{$_}, split //, uc($word); say $numeric;

    In this case, both the procedural and function approach are quite clear.

    It's very ironic that you're calling map unclear when your variable name indicates you're thinking in terms of a map.

      I think I prefer yours and 950927:

      my %map = ( ... ); $map{$_} = $_ for 0..9; my $numeric = join '', map $map{$_}, split //, uc($word); say $numeric;

      Walking the road to enlightenment... I found a penguin and a camel on the way.....
      Fancy a yourname@perl.me.uk? Just ask!!!
Re: map and grep or clear code?
by tobyink (Canon) on Jan 31, 2012 at 11:04 UTC

    Personally I'd find a simple regex s/// simpler than all of the above:

    use strict; use warnings; use 5.10.1; my $filter_clean = 'GAV18'; my %filter_map = ( A => 2, B => 2, # ... Y => 9, Z => 9, ); $filter_map{$_} = $_ for 0..9; (my $output = uc $filter_clean) =~ s{ (.) }{ $filter_map{$1} }exg; say $output;
      No need to extend the hash (with 0..9) :
      (my $output = $filter_clean) =~ s{ (\D) }{ $filter_map{uc $1} }exg;
      If the aim isn't to separate data and function :
      use strict; use warnings; use 5.10.1; my $filter_clean = 'GaV18'; sub filter2num { local $_=shift; s/[ABC] /2/igx; s/[DEF] /3/igx; s/[GHI] /4/igx; s/[JKL] /5/igx; s/[MNO] /6/igx; s/[PQRS]/7/igx; s/[TUV] /8/igx; s/[WXYZ]/9/igx; return $_; } say filter2num($filter_clean);

        Even something like:

        $filter_clean =~ tr/A-Z/22233344455566677778889999/;

        ought to do.

Re: map and grep or clear code?
by johngg (Canon) on Jan 31, 2012 at 11:36 UTC

    Like tobyink I think a regex solution is simpler and I would add the lower case letters to your look-up hash rather than uc'ing each letter or string in turn.

    use strict; use warnings; use 5.010; my @lettersPerButton = ( 3, 3, 3, 3, 3, 4, 3, 4 ); my @buttons = map { ( $_ ) x shift @lettersPerButton } 2 .. + 9; my %filterMap = map { $_ => shift @buttons } q{A} .. q{Z}; $filterMap{ lc( $_ ) } = $filterMap{ $_ } for q{A} .. q{Z}; my @toClean = qw{ GAV18 gAv18 peter Bill34 }; foreach my $filterClean ( @toClean ) { ( my $filter = $filterClean ) =~ s{([A-Za-z])}{$filterMap{ $1 }}g; say qq{$filterClean --> $filter}; }

    The output.

    GAV18 --> 42818 gAv18 --> 42818 peter --> 73837 Bill34 --> 245534

    I hope this is of interest.

    Cheers,

    JohnGG

Re: map and grep or clear code?
by choroba (Cardinal) on Jan 31, 2012 at 10:16 UTC
    I would use grep, but remove the and $filter_clean from inside its condition. If you really want to check it, do it just once before running grep, repeating it when the variable does not change is useless. Also, map returns a list, but you want to concatenate a string, so use join. If you add numbers to your %filter_map (e.g. by
    $filter_map{$_} = $_ for 0 .. 9;
    ), you can simplify it to
    $filter .= join q{}, map $filter_map{ uc $_ }, split //, $filter_clean +;
    which seems pretty clear to me.
Re: map and grep or clear code?
by Anonymous Monk on Jan 31, 2012 at 10:25 UTC

    Not sure why, but find myself not reaching for them ever.

    Simple, you're not a perl
    a real perl
    an idiomatic perl programmer yet :)

    Or as Modern Perl would say experienced perl hacker, not sure if he meant level 4 or 5 on the Seven Levels of Perl Mastery scale

    Why would I use below ...

    Because you think in terms of map and grep :)

    my %filter_map = do { my $ix = 'A'; map { $ix++ => $_ } ( map { ($_) x 3 } 2 .. 6 ), ( 8 ) x 3, ( 9 ) x 4, };

    Like a fighter, you think in terms of kicking and punching, not bending and expanding your knees and elbows while rotating your hips :)

      Nice code, but I miss 7.

        Nice code, but I miss 7.

        That sum''ich was mighty hungry to i axed 'im 'fore 'e ate 9

      I feel comfortable saying I'm somewhere in level 4 (Expert), but have not done a JAPH and had to look up cryptocontext.

      Level 5 and 6 look very cool!

      Walking the road to enlightenment... I found a penguin and a camel on the way.....
      Fancy a yourname@perl.me.uk? Just ask!!!
Re: map and grep or clear code?
by Eliya (Vicar) on Jan 31, 2012 at 10:37 UTC
    Advice? I prefer my first version for when I come back later.

    Not sure whether you want opinions on what other people would find preferable, or what we think that you should use.  In case of the latter, I think you've already answered the question yourself. If you find the procedural version easier to understand, then by all means stick with it — unless maybe you're anticipating that some potential future maintainer is going to have less difficulties with the functional variant.

    Personally, I think the functional style sometimes allows to express things more compactly (and thus it's less/easier to parse for those familiar with the style), but there's no point in using map and grep just for the sake of using them...

Re: map and grep or clear code?
by fisher (Priest) on Jan 31, 2012 at 10:14 UTC
    Well, I find myself comfortable with 'map' and 'grep', but please take in account that I'm using functional programming, scheme and erlang. But anyway, while your first version shows mechanics in detail, and I forced to understand it, -- the second seems more clear to my eyes. Is your question about personal preferences, right?
Re: map and grep or clear code?
by ghenry (Vicar) on Jan 31, 2012 at 12:00 UTC

    Thanks. Yes it was more about my personal choice and whether I'm actually growing with regards to my skill level. Everyones examples are clear and show how I can save my fingers but still be concise. I've got a ton of for loops that just go through an array and mung each element and push into a new one which I can now make clearer.

    I don't think I've done enough or stretched myself as it's been 8 years now :-)

    Walking the road to enlightenment... I found a penguin and a camel on the way.....
    Fancy a yourname@perl.me.uk? Just ask!!!
      I don't think I've done enough or stretched myself as it's been 8 years now :-)

      We all grow in our own time and at our own pace, and add "roots & shoots" according to our own need. ;-)

      HTH,

      planetscape

        What about "shoots and leaves?"