The Bear's Den

Enter at your own risk

Sum Tokens and Count Digits

Task 1: Alphabet Index Digit Sum

Submitted by: Mohammad Sajid Anwar


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.

Example 1

Input: $str = "abc", $k = 1
Output: 6

Conversion: a = 1, b = 2, c = 3 -> 123
Digit sum: 1 + 2 + 3 = 6

Example 2

Input: $str = "az", $k = 2
Output: 9

Conversion: a = 1, z = 26 -> 126
1st sum: 1 + 2 + 6 = 9
2nd sum: 9

Example 3

Input: $str = "cat", $k = 1
Output: 6

Conversion: c = 3, a = 1, t = 20 -> 3120
Digit sum: 3 + 1 + 2 + 0 = 6

Example 4

Input: $str = "dog", $k = 2
Output: 8

Conversion: d = 4, o = 15, g = 7 -> 4157
1st sum: 4 + 1 + 5 + 7 = 17
2nd sum: 1 + 7 = 8

Example 5

Input: $str = "perl", $k = 3
Output: 6

Conversion: p = 16, e = 5, r = 18, l = 12 -> 1651812
1st sum: 1 + 6 + 5 + 1 + 8 + 1 + 2 = 24
2nd sum: 2+4 = 6
3rd sum: 6

Solution

There is not much to consider in Perl as a scalar has a dual string / number nature.

Split the string into single characters, find their alphabetic indices and join.

Then split the number into its digits and add these. Repeat the last step $k times.

Perl

use strict;
use warnings;
use List::Util 'sum';
use experimental 'signatures';

sub alpha_index_digit_sum ($str, $k) {
    my $d = join '', map ord() - ord('a') + 1, split //, $str;
    $d = sum split //, $d for 1 .. $k;
    $d;
}

See the full solution to task 1.

J

A little more care is required in J as strings and numbers are not compatible and need to be converted into the proper type according to the desired operation:

Furthermore, an array cannot contain strings of different lengths. Within an array, strings are filled with spaces to a common maximum length.

Concatenating the digits of a list of numbers therefore requires these steps:

Calculating the digit sum (based on characters) may be done like this:

Assembling these parts as an adverb that produces a verb with k-fold repetition of the digit sum.

NB. alpha index repeated digit sum, use as:
NB. m airds string
NB. where m is the number of digit summations
NB. use boxed m to see intermediate results
NB. or _ to proceed to a fixed point
airds =: {{
    alpha =. a. {~ 97+i.26     NB. 'a...z'
    ai =. >:@(alpha&i.)        NB. 'a' -> 1, 'b' -> 2, ...
    join =. ;@(8!:0)           NB. (1 234 56) -> '123456'
    ds =. ":@(+/)@:("."0)      NB. '666' -> '18'
    ".@(ds^:u)@join@:ai@] f.
}}

1 airds 'abc'
NB. 6
(<4) airds 'fzzzzz'
NB. 62626262626 46 10 1
(<4) airds 'isssss'
NB. 91919191919 59 14 5

See the full solution.

Task 2: Valid Token Counter

Submitted by: Mohammad Sajid Anwar


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.

Example 1

Input: $str = "cat and dog"
Output: 3

Tokens: "cat", "and", "dog"

Example 2

Input: $str = "a-b c! d,e"
Output: 2

Tokens: "a-b", "c!", "d,e"
"a-b" -> valid (one hyphen between letters)
"c!"  -> valid (punctuation at end)
"d,e" -> invalid (punctuation not at end)

Example 3

Input: $str = "hello-world! this is fun"
Output: 4

Tokens: "hello-world!", "this", "is", "fun"
All satisfy the rules.

Example 4

Input: $str = "ab- cd-ef gh- ij!"
Output: 2

Tokens: "ab-", "cd-ef", "gh-", "ij!"
"ab-"   -> invalid (hyphen not surrounded by letters)
"cd-ef" -> valid
"gh-"   -> invalid
"ij!"   -> valid

Example 5

Input: $str = "wow! a-b-c nice."
Output: 2

Tokens: "wow!", "a-b-c", "nice."
"wow!"  -> valid
"a-b-c" -> invalid (more than one hyphen)
"nice." -> valid

Solution

There is room for the interpretation of this task. From the wording and the examples I reason the following conditions that define an invalid token:

I do not see any further restrictions.

This permits a wide range of valid tokens, such as 'R=(p-q)/(p+q)' or
'{}[]+*/;:_<>|@$#ÄÖÜ'.

Every of the above conditions can be put inside a negative look-ahead assertion anchored at the beginning of the string. Any string matching such an expression will be regarded as valid.

use strict;
use warnings;

sub valid_token_counter {
    my $digit = qr{.*\d};
    my $pre_h = qr{.*-(?<!\p{Ll}.)};
    my $post_h = qr{.*-(?!\p{Ll})};
    my $multi_h = qr{.*-.*-};
    my $punct = qr{.*[!.,].};
    my $valid = qr{
        ^
        (?!$digit)
        (?!$pre_h)
        (?!$post_h)
        (?!$multi_h)
        (?!$punct)
    }x;
    grep /$valid/, split /\s+/, shift;
}

In scalar context, the returned value of this function is the number of valid tokens and the list of valid tokens in list context.

See the full solution to task 2.