Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

numerology experiment

by orange (Beadle)
on Nov 26, 2007 at 15:48 UTC ( [id://653009]=perlquestion: print w/replies, xml ) Need Help??

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

hi
suppose every letter in the alphabet have a value as in the pseudo science of numerology, but not necessarily from 1 to 26
suppose i have a long sentence such as "aabceezazerrfde" and some one have told me that he wants to add just the values of some letters of choice as "aez" , the values of these letters are (7,2,26). i have the following approach, but i feel it is clumsy , are there other appproaches.
#!/usr/bin/perl use strict; my $str = "aabceezazerrfde"; my $wanted = "aez"; my @values = (7,2,26); my $counter = 0; my $tot = 0; my $letter = ''; my $indx; while ($counter < length($str) ) { $letter = substr($str, $counter, 1); $indx = index($wanted, $letter); if ( $indx != -1 ) { $tot = $tot + $values[$indx]; } $counter++; } print $tot;
the output is 81

Replies are listed 'Best First'.
Re: numerology experiment
by toolic (Bishop) on Nov 26, 2007 at 16:04 UTC
    Another way to do it is to store your wanted values in a hash and split your string into an array, as follows:
    #!/usr/bin/env perl use warnings; use strict; my $str = 'aabceezazerrfde'; my %vals = ( 'a' => 7, 'e' => 2, 'z' => 26 ); my @chars = split //, $str; my $tot = 0; for (@chars) { if (exists $vals{$_}) {$tot += $vals{$_}} } print "total = $tot\n";
Re: numerology experiment
by kyle (Abbot) on Nov 26, 2007 at 16:27 UTC

    Starting with your data, I get a solution similar to toolic's, but I use List::Util and List::MoreUtils.

    use List::Util qw( sum ); use List::MoreUtils qw( zip ); my $str = "aabceezazerrfde"; my $wanted = "aez"; my @values = (7,2,26); my @wanted = split //, $wanted; my %value_of = zip @wanted, @values; my $tot = sum map { $value_of{$_} || 0 } split //, $str;

    Note that if you use warnings (as you should), this will puke up "Use of uninitialized value in subroutine entry" for every letter in $str that is not in $wanted, but otherwise it works fine.

    Update: With a small change, no more warnings.

Re: numerology experiment
by TheForeigner (Initiate) on Nov 26, 2007 at 17:09 UTC
    I say, "when in doubt, map stuff." I used a hash to map letters to values... I also go 81 as an answer. You could also create your two arrays (wanted and values) and then make them into a hash before running this code:
    use strict; my $str = "aabceezazerrfde"; my %values = ('a' => 7, 'e' => 2, 'z' => 26); my $total = 0; foreach(split '',$str){ if($values{$_}){ $total += $values{$_}; } } print "Total: $total";
Re: numerology experiment
by RaduH (Scribe) on Nov 26, 2007 at 16:04 UTC
    Not sure it is really better but you could use a hash where you add the "value" of each letter (the letter is the key and your assigned number is the value for that key). You initialize you hash with all those numbers. Then you add a counter next to the value, to keep track of occurrences. Thus, at any given point your hash entry for letter P would be 234, 689 (P has value 234 and was found 689 times). When you're done combing your string you can collect all the data you need from the hash. Uses some more memory but makes browsing your string easier (I understand you may not be interested in all letters so feel free to extract only what you care for).

    This seems more Perl-style: use some more resources to make your life easier... not sure it's always a good approach but hey, this is Perl :)

    Hope this helps!

Re: numerology experiment
by GrandFather (Saint) on Nov 26, 2007 at 21:10 UTC

    for, map, grep and split provide a little synergy here:

    use strict; use warnings; my $str = "aabceezazerrfde"; my %wanted = (a => 7, e => 2, z => 26); my $tot = 0; my $counter = 0; $tot += $_ for map {++$counter; $wanted{$_}} grep {exists $wanted{$_}} + split //, $str; print "Found $counter letters totaling $tot\n";

    Prints:

    Found 9 letters totaling 81

    Update: s/,/;/ in map - bug fix, thanks toolic.


    Perl is environmentally friendly - it saves trees
      Why does this not result in a total of 81?

      The letter "a" appears 3 times: 3x7=21

      The letter "e" appears 4 times: 4x2=8

      The letter "z" appears 2 times: 2x26=52

      21+8+52=81, not 126.

        Because of a bug ;). map {++$counter, $wanted{$_}} should have been map {++$counter; $wanted{$_}} (note the s/,/;/).


        Perl is environmentally friendly - it saves trees
Re: numerology experiment
by Anonymous Monk on Nov 26, 2007 at 21:44 UTC
    perl -wMstrict -e "my $str = 'aabceezazerrfde'; my %values = qw(a 7 e 2 z 26); print scalar map { (0) x $values{$_} } grep exists $values{$_}, split +'', $str;" 81
Re: numerology experiment
by bobf (Monsignor) on Nov 27, 2007 at 05:25 UTC

    I couldn't resist posting a solution that doesn't use split, even if it uses string eval instead:

    use strict; use warnings; my $str = "aabceezazerrfde"; my %vals = ( a => 7, e => 2, z => 26 ); my $total = 0; while( my ( $char, $val ) = each %vals ) { my $count = eval "qw($str) =~ tr/$char//" or die $@; my $charval = $count * $val; $total += $charval; print "Found [$char] $count times ($count * $val = $charval)\n"; } print "Total = $total\n";
    Found [e] 4 times (4 * 2 = 8) Found [a] 3 times (3 * 7 = 21) Found [z] 2 times (2 * 26 = 52) Total = 81

Re: numerology experiment
by Muggins (Pilgrim) on Nov 29, 2007 at 11:33 UTC

    I'm late on this but here's a version I liked, for brevity:

    use strict; use warnings; my $str = "aabceezazerrfde"; my %wanted = (a => 7, e => 2, z => 26); my $tot = 0; $wanted{$_} && ($tot += $wanted{$_}) for (split //, $str); print "Total $tot\n";


    Better in some circumstances might be:

    exists $wanted{$_} && ($tot +=  $wanted{$_}) for (split //, $str);

    but I don't think it matters in this case. I discussed mixing "for" and "if" in one line with moritz and shmem recently, and I rather like it, though someone said it was too much logic for one line...

     ($tot +=  $wanted{$_})  if $wanted{$_} for (split //, $str);

    never seems to work...

    Cheers

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others chanting in the Monastery: (4)
As of 2024-04-25 07:50 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found