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!