This is my response to The Weekly Challenge #314.
-1
.
Input: $s1 = "abc", $s2 = "abb", $s3 = "ab"
Output: 2
Operation 1: Delete "c" from the string "abc"
Operation 2: Delete "b" from the string "abb"
Example 2:
Input: $s1 = "ayz", $s2 = "cyz", $s3 = "xyz"
Output: -1
Example 3:
Input: $s1 = "yza", $s2 = "yzb", $s3 = "yzc"
Output: 3
#! /usr/bin/env raku
unit sub MAIN ($s1 where $s1.chars > 0, # [1]
$s2 where $s2.chars > 0, # [1a]
$s3 where $s3.chars > 0, # [1b]
:v(:$verbose));
my @length = ($s1.chars, $s2.chars, $s3.chars); # [2]
my $min = @length.min; # [2a]
my $max = @length.max; # [2b]
if $min == $max # [3]
{
if ($s1 eq $s2 eq $s3) # [4]
{
say ": Same lenght, and all are equal" if $verbose;
say '0'; # [4a]
}
elsif $s1.substr(0,$min -1) eq $s2.substr(0,$min -1)
eq $s3.substr(0,$min -1) # [5]
{
say ": Same length, and all are equal when we drop the last character"
if $verbose;
say '3'; # [5a]
}
else # [6]
{
say ": Same length, but they are not equal" if $verbose;
say '-1'; # [6a]
}
}
elsif $max - $min > 1 # [7]
{
say ": Longest string is more than 1 character longer than the shortest"
if $verbose;
say '-1'; # [7a]
}
elsif $s1.substr(0,$min) eq $s2.substr(0,$min) eq $s3.substr(0,$min) # [8]
{
say ": Different length, but equal when we drop the last character in \
the long ones" if $verbose;
say @length.sum - ($min * 3); # [8a]
}
else # [9]
{
say ": Different length (min = max-1), dropping off 1 character does \
not help" if $verbose;
say '-1'; # [9a]
}
[1] The first [1], second [1a], and third [1b] strings, all of which must have at least one character.
[2]
Get the length of the three strings [2], then the minimun
length [2a] with min
, and the maximum length [2b] with max
.
See docs.raku.org/routine/min for more information about min
.
See docs.raku.org/routine/max for more information about max
.
[3] Do all the string have the same length?
[4] Are the three strings equal? Note the stacked eq
operators.
If so, we are done (without any operations).
[5] Are the three strings equal if we disregard the last character in each one? If so, print "3" [5a].
[6] The same length, but not [4] or [5], then they differ. Print "-1" [6a].
[7] Is the max length more than one longer than the minimum length? If so, print "-1" as we cannot chop off more than 1 character.
[8] The max length is one more than the min length when we come here. Are the strings equal when we drop the last character in the long one(s)? If so print the number of long strings (operations to perform).
[9] If we get here, the strings differ. print "-1".
Running it:
$ ./equal-strings abc abb ab
2
$ ./equal-strings ayz cyz xyz
-1
$ ./equal-strings yza yzb yzc
3
Looking good.
With verbose mode:
$ ./equal-strings -v abc abb ab
: Different length, but equal when we drop the last character in the long ones
2
$ ./equal-strings -v ayz cyz xyz
: Same length, but they are not equal
-1
$ ./equal-strings -v yza yzb yzc
: Same length, and all are equal when we drop the last character
3
Input: @list = ("swpc", "tyad", "azbe")
Output: 2
swpc
tyad
azbe
Column 1: "s", "t", "a" => non sorted
Column 2: "w", "y", "z" => sorted
Column 3: "p", "a", "b" => non sorted
Column 4: "c", "d", "e" => sorted
Total columns to delete to make it sorted lexicographically.
Example 2:
Input: @list = ("cba", "daf", "ghi")
Output: 1
Example 3:
Input: @list = ("a", "b", "c")
Output: 0
This challenge can be divided in two parts:
#! /usr/bin/env raku
unit sub MAIN (*@list where @list.elems > 1 && ( [==] @list>>.chars ), # [1]
:v(:$verbose));
my $cols = @list[0].chars; # [2]
my @cols; # [3]
for @list -> $string # [4]
{
for ^$cols -> $index # [4a]
{
@cols[$index] ~= $string.substr($index, 1); # [4b]
}
}
say ": Columns: { @cols.raku }" if $verbose;
my $deleted = 0; # [5]
for @cols -> $column # [6]
{
my $sorted = $column.comb.sort.join; # [7]
print ": Column: " if $verbose;
if $column ne $sorted # [8]
{
$deleted++; # [8a]
say " => non sorted" if $verbose;
}
elsif $verbose
{
say " => sorted";
}
}
say $deleted; # [9]
[1] A slurpy array for the list,
with at least 2 elements. The elements must have the same length (number
of characters). We use ==
in combination with the Reduction
Metaoperator []
to ensure that they are all equal.
See
docs.raku.org/language/operators#Reduction_metaoperators for more
information about the Reduction Metaoperator []
.
[2] Get the number of columns.
[3] The partial result, the columns (the first bullet point), will end up here.
[4] Iterate over the strings, and then the indices (of the characters in the string) [4a]. Append the character at that position in the string to the correct column string [4b].
[5] Number of deleted columns.
[6] Iterate over the columns.
[7] Get the sorted version of the column string. First comb
to
split the string into an array of characters, then sort
to sort
the characters (by the Unicode codepoint), and finally join
to
glue the characters into a string again.
[8] Do the column string and the sorted version differ? If so, delete the column (or rather, count it as deleted).
[9] Print the deleted number of columns.
Running it:
$ ./sort-column swpc tyad azbe
2
$ ./sort-column cba daf ghi
1
$ ./sort-column a b c
0
Looking good.
With verbose mode:
$ ./sort-column -v swpc tyad azbe
: Columns: ["sta", "wyz", "pab", "cde"]
: Column: => non sorted
: Column: => sorted
: Column: => non sorted
: Column: => sorted
2
$ ./sort-column -v cba daf ghi
: Columns: ["cdg", "bah", "afi"]
: Column: => sorted
: Column: => non sorted
: Column: => sorted
1
$ ./sort-column -v a b c
: Columns: ["abc"]
: Column: => sorted
0
And that's it.