Weekly Challenge 314 Task 2
Sort Columns
These are my workings for a solution to the Weekly Challenge Week 314 Task 2[1].
Task 2: Sort Columns
You are given a list of strings of same length.
Write a script to make each column sorted lexicographically by deleting any non sorted columns.
Return the total columns deleted.
To get the columns, or the same positions in the strings collected, I use zip where a character is taken from each string in turn:
strings = ("swpc", "tyad", "azbe")
columns = [c for c in zip(*strings)]
columns
[('s', 't', 'a'), ('w', 'y', 'z'), ('p', 'a', 'b'), ('c', 'd', 'e')]
To filter or delete the column I compare the sorted with the original:
columns_sorted = [c for c in zip(*strings) if sorted(c) == list(c)]
columns_sorted
[('w', 'y', 'z'), ('c', 'd', 'e')]
This is how I would turn the columns back to strings with the non sorted deleted:
strings_sorted_columns = ["".join(r) for r in zip(*columns_sorted)]
strings_sorted_columns
['wc', 'yd', 'ze']
The problem asks to return the number of columns deleted so the above operations really aren’t necessary.
This is how I would return a count of deleted columns:
columns_deleted = sum(1 for c in zip(*strings) if sorted(c) != list(c))
columns_deleted
2
The final function looks like this:
#!/usr/bin/env python3
def sort_columns(*strings):
""" Given a list of strings of same length, make each column sorted
lexicographically by deleting any non sorted columns, return the total
columns deleted.
>>> sort_columns("swpc", "tyad", "azbe")
2
>>> sort_columns("cba", "daf", "ghi")
1
>>> sort_columns("a", "b", "c")
0
"""
return sum(1 for c in zip(*strings) if sorted(c) != list(c))
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Trying:
sort_columns("swpc", "tyad", "azbe")
Expecting:
2
ok
Trying:
sort_columns("cba", "daf", "ghi")
Expecting:
1
ok
Trying:
sort_columns("a", "b", "c")
Expecting:
0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.sort_columns
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Perl Solution
Is the Array::Compare module the best way to compare 2 lists in Perl?
#!/usr/bin/env perl
use v5.35;
use Test2::Bundle::More;
use List::Util qw/zip/;
use Array::Compare;
my $comp = Array::Compare->new;
sub sortColumns{
my @strings = @_;
my $count = 0;
my @strings_split = map { [split //, $_] } @strings;
for my $c (zip(@strings_split)){
my @sorted = sort @$c;
if (!$comp->compare($c, \@sorted)) {
$count++;
}
}
return $count;
}
is(sortColumns("swpc", "tyad", "azbe"), 2, "Example 1");
is(sortColumns("cba", "daf", "ghi"), 1, "Example 2");
is(sortColumns("a", "b", "c"), 0, "Example 3");
done_testing();
ok 1 - Example 1
ok 2 - Example 2
ok 3 - Example 3
1..3