The weakest split
Tags: perl, python, theweeklychallenge
Published: 2024-01-28 11:05:55

## Weekly Challenge 253

Each week Mohammad S. Anwar sends out [The Weekly Challenge](https://theweeklychallenge.org/), a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.

[Challenge](https://theweeklychallenge.org/blog/perl-weekly-challenge-253/), [My solutions](https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-253/sgreen)

## Task 1: Split Strings

### Task

You are given an array of strings and a character separator.

Write a script to return all words separated by the given character excluding empty string.

### My solution

This is a little more straight forward in Python than Perl. In Python, I concatenate the `words` with the `sep` separator. I then split on the separator, excluding any empty words.

```python
def split_strings(words, sep):
    combined = sep.join(words)

    return [ w for w in combined.split(sep) if w != '']
```

In Perl, the [split](https://perldoc.perl.org/functions/split) function takes a regular expression. Therefore I need to add an extra step to escape any [metacharacters that have special meaning](https://perldoc.perl.org/perlrequick#Simple-word-matching).

```perl
sub split_strings ( $words, $sep ) {
    my $combined = join( $sep, @$words );

    if ( index( '{}[]()^$.|*+?\\', $sep ) != -1 ) {
        $sep = "\\$sep";
    }

    my @result = grep { length($_) } split( /$sep/, $combined );
    return \@result;
}
```

### Examples

```bash
$ ./ch-1.py one.two.three four.five six .
"one", "two", "three", "four", "five", "six"

$ ./ch-1.py '$perl$$' '$$raku$' '$'
"perl", "raku"
```

## Task 2: Weakest Row

### Task

You are given an m x n binary matrix i.e. only `0` and `1` where `1` always appear before `0`.

A row `i` is weaker than a row `j` if one of the following is true:

1. The number of `1`s in row `i` is less than the number of `1`s in row `j`.
1. Both rows have the same number of `1` and `i < j`.

### My solution

For this task I take the input as a json string, which should be any array of arrays of ones and zeros. The first thing I do is call the `validate_matrix` function, which does three checks:

1. All rows have the same number of columns.
1. All values are either `0` or `1`
1. No `1` appears after a `0`.

I then have a one liner to return the result.

```python
def weakest_row(matrix):
    validate_matrix(matrix)

    return sorted(range(len(matrix)), key=lambda i: sum(matrix[i]))
```

Lets unpack that line

1. `range(len(matrix))` simply returns a list from `0` to one less than the length of array.
1. `sum(maxtrix[i]))` will calculate the number of `1`s in the row.
1. `key=lambda i: ...` will sort by the number of 1s (lowest first).
1. In Python, sorting is [stable](https://docs.python.org/3/howto/sorting.html#sort-stability-and-complex-sorts). This means if two rows have the same sum, the original order is preserved.

The Perl solution follows the same logic, albeit with slightly different syntax. Using `<=>` and `||` is well documented in the [sort](https://perldoc.perl.org/functions/sort) function.

```perl
 my @sorted = sort {
        sum( @{ $matrix->[$a] } ) <=> sum( @{ $matrix->[$b] } ) || $a <=> $b
    } ( 0 .. $#$matrix );
```

### Examples

```bash
$ ./ch-2.py "[ [1, 1, 0, 0, 0], [1, 1, 1, 1, 0], [1, 0, 0, 0, 0], [1, 1, 0, 0, 0], [1, 1, 1, 1, 1]]"
(2, 0, 3, 1, 4)

$ ./ch-2.py "[ [1, 0, 0, 0], [1, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 0] ]"
(0, 2, 3, 1)
```