Steven's Homepage

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

References

  1. Weekly Challenge Week 314 Task 2
  2. zip
  3. Array::Compare
  4. List::Util::zip