Andrew Shitov Weekly Review: Challenge - 273

Tuesday, Jun 18, 2024| Tags: Raku

Raku Solutions Weekly Review


Note from the Reviewer

This week’s review has been generated by ChatGPT, an AI language model. The AI has analyzed the submitted solutions for both tasks and grouped them based on the methods and features used. It also includes the AI's own solutions for each task. While every effort has been made to ensure the accuracy and clarity of the review, please feel free to reach out with any questions or feedback. We hope you find the insights and analyses helpful! (This note was AI-generated too.)

Task 1: Percentage of Character

This week’s challenge was to write a program that returns the percentage, nearest whole, of a given character in a given string. The problem is straightforward and involves simple string manipulation, but the solutions submitted by various participants showcase a variety of approaches in Raku. Let’s group these solutions based on the features and methods they used.

1. Using grep

Several participants used the grep method to count the occurrences of the character in the string. The grep method filters elements of a list based on a given condition.

Documentation for grep.

# Luca Ferrari
sub MAIN( Str $string, Str $char where { $char.chars == 1 } ) {
    ( $string.comb.grep( * ~~ $char ).elems / $string.comb.elems * 100 ).Rat.round.say;
}

# Joelle Maslak
sub MAIN(Str:D $str where $str.chars > 0, Str:D $char where $char.chars == 1) {
    my $charcount = $str.comb.grep($char);
    printf("Percentage of times character apears in string %.0f%%
", 100.0*$charcount/$str.chars);
}

# Ulrich Rieke
my $count = $word.comb.grep( {$_ eq $needle} ).elems;
say (( $count / $word.chars ) * 100).round;

2. Using Bag

Another popular approach was to use the Bag method, which is particularly useful for counting occurrences of elements in a list. Bag is a multi-set that tracks the number of occurrences of each element.

Documentation for Bag

# Arne Sommer
unit sub MAIN ($str where $str.chars > 0, $char where $char.chars == 1);
say ( (100 * $str.comb.Bag{$char} / $str.chars) + 0.5).int;

# BarrOff
sub percentage-of-character(Str $str, Str $char --> Int) {
    return 0 unless $str.contains($char);
    ceiling(100 * Bag($str.comb){$char} ÷ $str.chars)
}

# Jan Krnavek
sub percentage-of-character ($str,:$char) {
    $str.comb
    andthen .Bag
    andthen .{$char}/.total
    andthen 100 * $_
    andthen .round
}

3. Using comb and Basic Arithmetic

Several solutions relied on the comb method to split the string into characters and then used basic arithmetic to calculate the percentage. comb splits a string into a list of substrings matching a given pattern.

Documentation for comb

# Andrew Shitov
my @tests = perl => 'e', java => 'a', python => 'm', ada => 'a', ballerina => 'l', analitik => 'k';
for @tests -> $pair {
    say (100 * $pair.key.comb($pair.value) / $pair.key.comb).round;
}

# Ali Moradi
sub percentage-of-character($str,$c) {
  my $count = $str.comb($c).elems;
  round(100 * $count / $str.chars)
}

# Laurent Rosenfeld
sub percent ($str, $char) {
    my $count = 0;
    for $str.comb -> $ch {
        $count++ if $ch eq $char;
    }
    return (($count * 100) / $str.chars).round;
}

4. Using indices

A few participants used the indices method, which returns the indices of the matching elements, to count occurrences and calculate the percentage. indices returns the positions of all matches of a pattern in a string, and the count of these indices gives the number of occurrences.

cumentation for indices

# Mark Anderson
sub perc-of-char($str, $char) {
    round 100 * $str.indices($char) / $str.chars
}

# Bruce Gray
sub task1 ( $str, $char --> UInt ) {
    my UInt $count = +$str.comb($char);
    return round( 100 * $count / $str.chars );
}

5. Using classify

Jaldhar H. Vyas used the classify method, which categorizes elements based on a given condition. classify returns a hash where the keys are the results of the classification routine and the values are lists of elements that fall into each category.

Documentation for classify

# Jaldhar H. Vyas
sub MAIN(Str $str, Str $chr) {
    $str.comb.classify({ $_ }, into => my %freq);
    say %freq{$chr}:exists ?? (%freq{$chr}.elems / $str.chars * 100).round !! 0;
}

6. Mixed Approaches and Advanced Techniques

Some participants used a combination of methods and advanced techniques to solve the problem, adding robustness and flexibility to their solutions.

# Robert Ransbottom
sub task( $word, $letter) {
    my @w = $word.comb;
    (100 × @w.grep( $letter) ÷ @w).round;
}

# Athanasius
sub find-percentage($str, $orig-char, $ignore-case) {
    my UInt $count = 0;
    my Str  $char  = $ignore-case ?? $orig-char.lc !! $orig-char;
    for $str.split: '', :skip-empty -> Str $orig-c {
        my Str $c  = $ignore-case ?? $orig-c.lc    !! $orig-c;
        ++$count if $c eq $char;
    }
    return (($count / $str.chars) * 100).round;
}

# Packy Anderson
sub charPercent($str, $char) {
    return round(( $str.comb($char).elems / $str.chars ) * 100);
}

ChatGPT’s solution

Here you will find a solution to this task generated by ChatGPT:

sub percentage-of-character($str, $char) {
    my $count = $str.comb($char).elems;
    return round(100 * $count / $str.chars);
}

my @tests = (
    ['perl', 'e', 25],
    ['java', 'a', 50],
    ['python', 'm', 0],
    ['ada', 'a', 67],
    ['ballerina', 'l', 22],
    ['analitik', 'k', 13]
);

for @tests -> $test {
    my ($str, $char, $expected) = $test;
    my $result = percentage-of-character($str, $char);
    say "Input: \$str = \"$str\", \$char = \"$char\"";
    say "Output: $result (Expected: $expected)";
    say $result == $expected ?? 'Test Passed' !! 'Test Failed';
    say '';
}

When you run the code, you get the following output:

$ raku 1.raku
Input: $str = "perl", $char = "e"
Output: 25 (Expected: 25)
Test Passed

Input: $str = "java", $char = "a"
Output: 50 (Expected: 50)
Test Passed

Input: $str = "python", $char = "m"
Output: 0 (Expected: 0)
Test Passed

Input: $str = "ada", $char = "a"
Output: 67 (Expected: 67)
Test Passed

Input: $str = "ballerina", $char = "l"
Output: 22 (Expected: 22)
Test Passed

Input: $str = "analitik", $char = "k"
Output: 13 (Expected: 13)
Test Passed

Summary

This week’s challenge highlighted the simplicity and power of Raku's string manipulation capabilities. Most solutions utilized methods like comb, grep, Bag, and indices to count occurrences of the given character in the string, followed by calculating the percentage. The variations in implementations demonstrate Raku’s flexibility and the different ways programmers can approach a problem. Whether using concise one-liners or more detailed subroutines, each solution showcases Raku’s expressive syntax and rich standard library. Great job to all participants!

Task 2: B After A

This week’s second challenge was to write a script that returns true if there is at least one ‘b’, and no ‘a’ appears after the first ‘b’ in the given string. This problem is a bit more complex than the first task and involves string pattern matching and manipulation. Let’s group the solutions based on the features and methods they used.

1. Using Regular Expressions

Several participants used regexes to solve the problem. This method allows for a concise solution by leveraging Raku's powerful regex capabilities.

Explanation of Regexes

Regular expressions are patterns used to match character combinations in strings. Raku's regex syntax is powerful and expressive, making it well-suited for this task.

Documentation for Regexes

Matching Specific Patterns

Some solutions directly match the required pattern using regexes. For instance, checking if there is a 'b' followed by no 'a'.

# Arne Sommer
unit sub MAIN ($str where $str.chars > 0);

# Check if the string contains 'b'
if $str ~~ /b/ {
  # Split the string at the first 'b' and check the part after it
  my $after = $str.split(/b/, 2)[1];

  # If the part after 'b' does not contain 'a', print 'true'
  if $after !~~ /a/ {
    say 'true';
    exit;
  }
}
say 'false';
# Luca Ferrari
sub MAIN( Str $string where { $string.chars > 0 } ) {
    'True'.say and exit if ( $string ~~ / b / && $string !~~ / b .* a / );
    'False'.ay;
}

Using Extended Patterns

Other solutions use more complex patterns to ensure that the entire string matches the required conditions.

# Laurent Rosenfeld
sub b-after-a ($str) {
    return $str ~~ /^ <-[b]>* b <-[a]>* $/ ?? True !! False;
}

for <aabb abab aaa bbb> ->  $test {
    printf "%-5s => ", $test;
    say b-after-a $test;
}
# Joelle Maslak
sub MAIN(Str:D $str) {
    my $match = $str ~~ m/^ <-[ b ]>* 'b' <!before 'a'>/;
    say "Output: " ~ ($match ?? "true" !! " false");
}

2. Simplified Logic

Some participants opted for a simplified logic to check if the string contains 'bb', which directly solves the problem for the given examples. This approach may not fully generalize but works for the provided test cases.

# Andrew Shitov
my @tests = < aabb abab aaa bbb >;
for @tests -> $test {
    say lc ?($test ~~ / bb /);
}

# Ali Moradi
sub b-after-a($str) {
  ?($str ~~ /bb/)
}
say b-after-a('aabb');
say b-after-a('abab');
say b-after-a('aaa');
say b-after-a('bbb');

3. Using String Manipulation and Iteration

Another group of participants used string manipulation and iteration to check the conditions manually. This approach is more explicit and provides control over each step of the process.

Documentation for String Manipulation

Checking with Iteration

These solutions manually check each character in the string, keeping track of whether a 'b' has been seen and ensuring no 'a' appears after it.

# Mark Anderson
sub b-after-a($str) {
    $str ~~ / ^ <-[b]>* b <-[a]>* b <-[a]>* $ /
}
sub b-after-a-pos($str) {
    my $b = $str ~~ m:1st / b / || return False;
    my $a-after-b = $str ~~ m:c($b.pos):1st / a /;
    my $b-after-b = $str ~~ m:c($b.pos):1st / b /;
    $b-after-b and not $a-after-b
}
sub b-after-a-indices($str) {
    my @a = $str.indices('a');
    my @b = $str.indices('b');
    @b > 1 and all(@a) < @b.head
}

4. Using Indices

A few participants used the different index-related methods to find positions of 'a' and 'b' in the string and then determined the result based on these positions.

# Robert Ransbottom
sub task( $word) {
    my @w = $word.comb;
    without my $b-k = @w.first( 'b', :k) { return False }
    with @w[++$b-k..^@w].first( 'a') { return False }
    True;
}

# Roger Bell-West
sub baftera($a) {
    my $firstb = index($a, "b");
    if (!$firstb.defined) {
        return False;
    }
    my $lasta = rindex($a, "a");
    if (!$lasta.defined) {
        return True;
    }
    return $lasta < $firstb;
}

# Packy Anderson
sub bAfterA($str) {
  my $seen_b = False;
  for $str.comb -> $c {
    if ($seen_b) {
      if ($c eq 'a') {
        return False;
      }
    }
    elsif ($c eq 'b') {
      $seen_b = True;
    }
  }
  return $seen_b;
}

ChatGPT’s solution

Here you will find a solution to this task generated by ChatGPT:

sub b-after-a($str) {
    my $b-seen = False;
    for $str.comb -> $c {
        if $c eq 'b' {
            $b-seen = True;
        }
        elsif $b-seen && $c eq 'a' {
            return False;
        }
    }
    return $b-seen;
}

my @tests = (
    ['aabb', True],
    ['abab', False],
    ['aaa', False],
    ['bbb', True]
);

for @tests -> $test {
    my ($str, $expected) = $test;
    my $result = b-after-a($str);
    say "Input: \$str = \"$str\"";
    say "Output: " ~ ($result ?? 'true' !! 'false') ~ " (Expected: " ~ ($expected ?? 'true' !! 'false') ~ ")";
    say $result == $expected ?? 'Test Passed' !! 'Test Failed';
    say '';
}

Run the code to see its output:

$ raku 2.raku
Input: $str = "aabb"
Output: true (Expected: true)
Test Passed

Input: $str = "abab"
Output: false (Expected: false)
Test Passed

Input: $str = "aaa"
Output: false (Expected: false)
Test Passed

Input: $str = "bbb"
Output: true (Expected: true)
Test Passed

Summary

This week’s challenge showcased a variety of approaches to solve a problem involving string pattern matching and manipulation. The solutions utilized methods like regular expressions, string manipulation, and the indices method to determine if a string meets the given conditions. The variations in implementations demonstrate Raku's flexibility and the different ways programmers can approach a problem. Whether using concise regexes or more detailed iteration, each solution highlights Raku's expressive syntax and rich standard library. Great job to all participants!

SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.

Contact with me