DEV Community

Simon Green
Simon Green

Posted on

Weekly Challenge: Counting the index

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.

Challenge, My solutions

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"
            )
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
    )
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)