Weekly Challenge #081 Task #1 :: Raku
Tags: challenge, raku, perl, perlweeklychallenge
Published: 2020-10-05 12:20:57

[TASK #1 › Common Base String](https://perlweeklychallenge.org/blog/perl-weekly-challenge-081/#TASK1)
Submitted by: Mohammad S Anwar

```
You are given 2 strings, $A and $B.

Write a script to find out common base strings in $A and $B.

    A substring of a string $S is called base string if repeated concatenation of the substring results in the string.
```

```
Example 1:

Input:
    $A = "abcdabcd"
    $B = "abcdabcdabcdabcd"

Output:
    ("abcd", "abcdabcd")

Example 2:

Input:
    $A = "aaa"
    $B = "aa"

Output:
    ("a")
```

My usual starting point is how we get the input?
we are given two string. so how about get two individual variables?

```perl
sub MAIN ( Str \A, Str \B ) {
   say A, ",", B;
}
```
```shell
shell> raku ch-1.raku a aaa
a,aaa
```

BTW, if we don't want to (or won't) change the value of variable
we can use "\varname" syntax, and "varname" is now immutable.
so, "A", "B" are both immutable variables now.  

Most principle part of this challenge is "how we get sub string of a string?" and no problem, we have [substr method](https://docs.raku.org/routine/substr)

```perl
sub MAIN ( Str \A, Str \B ) {
   B.substr( 0 .. 1 ).say;
}
```
```shell
shell> raku ch-1.raku a aaa
aa
```

as you can see "0 .. 1" is a [Range](https://docs.raku.org/type/Range) and they are index numbers in here.
.. so we have to say "'table for 1' to a waiter when you have 'a' company" ... no... please don't.. 

the base word must contains the **substr** from the beginning of each words otherwise it couldn't be a base word

before we go further, one more thing we should know about a handy operator [**"x"** String repetition operator](https://docs.raku.org/routine/x)

```perl
shell> raku # interactive shell for raku 😍
To exit type 'exit' or '^D'
> "o" x 5
ooooo
```

 It does not make sense to make a longer base string than any of given string so I added some restriction.

```perl
sub MAIN ( Str \A, Str \B ) {
    my ( @answer, $shorter );

    # shorter version of bellow
    # $shorter = A.chars < B.chars ?? A !! B
 
    if A.chars < B.chars {
        $shorter = A;
    }
    else {
        $shorter = B;
    }

    for 1..$shorter.chars -> $num-char {
        my $mcb = $shorter.substr( ^$num-char ); # mcb: maybe common base string
        #        `-> another way of A.substr( 0..$num-char);

        next unless A.chars %% $num-char and B.chars %% $num-char;

        if ( A eq $mcb x ( A.chars div $num-char )
            and
            B eq $mcb x ( B.chars div $num-char ) ) {
            @answer.push( $mcb );
        }
    }
    @answer.say;
}
```

okay. this is "a" solution. 


Raku has really excellent documentation.
please check the document if we are curious about something.

**%%** operator : https://docs.raku.org/routine/$PERCENT_SIGN$PERCENT_SIGN

and if we add more (really) convenient sugar onto the
comparison block, it would be changed ...

```perl
...
        if ( A eq $mcb x ( A.chars div $num-char )
            and
            B eq $mcb x ( B.chars div $num-char ) ) {
            @answer.push( $mcb );
...
```

becomes

```perl
...
        if (A,B).map(
            -> $str {
                $mcb x ( $str.chars div $num-char ) } ).all == True {
            @answer.push( $mcb );
...
```

good. looks trendy functional programming. :-] 
".all" looks magic for me. we should try.
how about *any* ?

```perl
shell> raku
To exit type 'exit' or '^D'
> any( 1 == 0, "abc" eq "def", ("I love Raku".substr(0,5) eq ("I love Perl".substr(0,5)))) == True
any(False, False, True)
> (any( 1 == 0, "abc" eq "def", ("I love Raku".substr(0,5) eq ("I love Perl".substr(0,5)))) == True).so
True
```

but one more thing ....
there is a [**gcd**](https://docs.raku.org/routine/gcd) in Raku
e.g. greatest common divisor

A, B string must have the length of multiple of common divisor.

```perl
shell> raku
To exit type 'exit' or '^D'
> "abc".chars gcd "abcabc".chars
3
```

so I could make another solution by using new friend "gcd"

```perl
sub MAIN ( Str \A, Str \B ) {
    my @words = A, B;
    my @answer;

    my $gcd  = A.chars gcd B.chars;

    for 1..$gcd -> $maybe-cd {
        if $gcd %% $maybe-cd {
            note "$maybe-cd is common divisor";

            my $mcb = A.substr(^$maybe-cd);
            if @words.map(
                { $mcb x ($_.chars div $maybe-cd)
                  eq
                  $_ } ).all == True {
                note "found a base substring: $mcb";
                @answer.push( $mcb );
            }
        }
    }
    note "therefore:";
    @answer.join(", ").put;
}
```
```shell
shell> raku ch-1.blog.raku "abcdabcd" "abcdabcdabcdabcd"
1 is common divisor
2 is common divisor
4 is common divisor
found a base substring: abcd
8 is common divisor
found a base substring: abcdabcd
therefore:
abcd, abcdabcd

```

and... one more solution which is based on the gcd and [**indices**](https://docs.raku.org/routine/indices)
I like this one most.

```perl
sub MAIN(*@a) {
    say (1..([gcd] @a>>.chars)).
    map(->\k{my \w = @a[0].substr(^k);
          next if any @a.map({.indices(w).elems!= .chars/k});
          w } )
}
```

 More explain needed due to more concept goes through the code, but I'm still learning raku so... it is something like ...
```
> ("what I told" ~~ True, "today" ne "tommorrow", "I don't know something but it's working so I used.".so eq True).all.so
False
```

so, please wait for another episode :-)

Thank you ~~ !!!