Weekly Challenge 365
Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.
Task 1: Alphabet Index Digit Sum
Task
You are given a string $str consisting of lowercase English letters, and an integer $k.
Write a script to convert a lowercase string into numbers using alphabet positions (a=1 … z=26), concatenate them to form an integer, then compute the sum of its digits repeatedly $k times, returning the final value.
My solution
This is a task of two parts. The first is to take the letters from input_string (as str is a reserved word in Python) to create a number. For this I use string.ascii_lowercase.index(letter)+1 to get each letter and append it to the digits variable. The +1 is because the letters start at 1, not 0.
def aid_sum(input_string: str, k: int) -> int:
digits = ''
for letter in input_string:
try:
digits += str(string.ascii_lowercase.index(letter)+1)
except ValueError:
raise ValueError(
f"The character '{letter}' does not appear to be a lower case letter"
)
The second part is to compute the sums of all the digits a specified number of times. For this I have a loop that performs this. It's a little clunky as Python treats strings and integers differently. If I have a single digit, I exit the loop early as further repetitions won't change the result.
for _ in range(k):
digits = str(sum(int(i) for i in digits))
if len(digits) == 1:
break
return int(digits)
As Perl doesn't care about strings vs integers (with a few exceptions), the code is more straight forward. The index function is used to find the position of the letter in the alphabet.
sub main ( $input_string, $k ) {
my $alphabet = join( "", "a" .. "z" );
my $digits = '';
foreach my $letter ( split //, $input_string ) {
my $idx = index( $alphabet, $letter );
if ( $idx == -1 ) {
die
"The character '$letter' does not appear to be a lower case letter\n";
}
$digits .= $idx + 1;
}
foreach ( 1 .. $k ) {
$digits = sum( split //, $digits );
}
say $digits;
}
Examples
$ ./ch-1.py abc 1
6
$ ./ch-1.py az 2
9
$ ./ch-1.py cat 1
6
$ ./ch-1.py dog 2
8
$ ./ch-1.py perl 3
6
Task 2: Valid Token Counter
Task
You are given a sentence.
Write a script to split the given sentence into space-separated tokens and count how many are valid words. A token is valid if it contains no digits, has at most one hyphen surrounded by lowercase letters, and at most one punctuation mark (!, ., ,) appearing only at the end.
My solution
This is a challenge where regular expression can be used to solve the problem. In both the Python and Perl solution, the regular expression used is ^[a-z]+(\-[a-z]+)?[!,\.]?$.
Breaking each part down:
-
^indicate the start of the string -
[a-z]+means one or more lower case letters -
(\-[a-z]+)?means optionally (the question mark) a hyphen and one or more lowercase letters. -
[!,\.]?means optionally a exclamation mark, comma or full stop. -
$means the end of the string.
This is a one liner in Python
def valid_token_counter(input_string: str) -> int:
return sum(
1 for word in input_string.split()
if re.search(r'^[a-z]+(\-[a-z]+)?[!,\.]?$', word)
)
The Perl solution is also one line (and an extra one to display the answer). The grep function returns the number of matches in a scalar context.
sub main ($input_string) {
my $count = grep { /^[a-z]+(\-[a-z]+)?[!,\.]?$/ } split /\s+/,
$input_string;
say $count;
}
Examples
$ ./ch-2.py "cat and dog"
3
$ ./ch-2.py "a-b c! d,e"
2
$ ./ch-2.py "hello-world! this is fun"
4
$ ./ch-2.py "ab- cd-ef gh- ij!"
2
$ ./ch-2.py "wow! a-b-c nice."
2
Top comments (0)