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
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";
| [reply] [d/l] |
Re: numerology experiment
by kyle (Abbot) on Nov 26, 2007 at 16:27 UTC
|
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. | [reply] [d/l] [select] |
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";
| [reply] [d/l] |
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! | [reply] |
Re: numerology experiment
by GrandFather (Saint) on Nov 26, 2007 at 21:10 UTC
|
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
| [reply] [d/l] [select] |
|
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.
| [reply] |
|
| [reply] [d/l] [select] |
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
| [reply] [d/l] |
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
| [reply] [d/l] [select] |
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
| [reply] [d/l] [select] |
|
|