I’ve been doing the Weekly
Challenges. The
latest
involved various analyses of strings. (Note that this ends today.)
Task 1: Sum of Frequencies
You are given a string consisting of English letters.
Write a script to find the vowel and consonant with maximum
frequency. Return the sum of two frequencies.
In Rust there's the lovely counter crate, but elsewhere I had to do
it the hard way. Thus Perl:
sub sumoffrequencies($a) {
my $vw = 0;
my $cn = 0;
Built a table of letters and frequencies.
my %cc;
foreach my $c (split '', $a) {
$cc{$c}++;
}
my @cv = reverse sort values %cc;
In decreasing frequency order, look at each letter.
foreach my $n (@cv) {
while (my ($c, $ni) = each %cc) {
if ($ni == $n) {
Identify it as a vowel or a consonant, and if it's the first one,
count it.
if ($c eq 'a' || $c eq 'e' || $c eq 'i'|| $c eq 'o' || $c eq 'u') {
if ($vw == 0) {
$vw = $n;
}
} else {
if ($cn == 0) {
$cn = $n;
}
}
If we have counts for both, bail out. (Not necessary but saves time.)
if ($vw > 0 && $cn > 0) {
last;
}
}
}
if ($vw > 0 && $cn > 0) {
last;
}
}
And return the total.
$vw + $cn;
}
I've finally got round to adding support for this data type (known as
a counter, multiset or bag) to my PostScript libraries. Same basic
algorithm, but the heavy lifting is done by the library. (It has all
the functionality of the Rust counter crate that inspired it, and
the Python Counter type that inspired that. It won't do random
weighted samples, though, due to the lack of a decent random number
source in PostScript.)
/sumoffrequencies {
0 dict begin
/vw 0 def
/cn 0 def
s2a tocounter counter.most_common_ordered {
aload pop
/n exch def
/c exch def
c 97 eq
c 101 eq
c 105 eq
c 111 eq
c 117 eq
or or or or {
vw 0 eq {
/vw n def
} if
} {
cn 0 eq {
/cn n def
} if
} ifelse
vw 0 gt cn 0 gt and {
exit
} if
} forall
vw cn add
end
} bind def
Task 2: Reverse Degree
You are given a string.
Write a script to find the reverse degree of the given string.
For each character, multiply its position in the reversed alphabet
("a" = 26, "b" = 25, …, "z" = 1) with its position in the string.
Sum these products for all characters in the string to get the
reverse degree.
Fairly straightforward algorithm. In Crystal:
def reversedegree(a)
t = 0
Get a zero value for the code conversion, one step beyond "z".
z0 = 'z'.ord + 1
Look at each character and its position.
a.chars.each_with_index do |c, i|
Add the difference between z0 and character value, multiplied by its
(1-based) position.
t += (z0 - c.ord) * (1 + i)
end
t
end
Full code on
codeberg.