DEV Community

Simon Green
Simon Green

Posted on

The Weekly Challenge: Grep, set and match

Weekly Challenge 381

Each week Mohammad S. Anwar sends out The Weekly Challenge, 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. Unless otherwise stated, Copilot (and other AI tools) have NOT been used to generate the solution. It's a great way for us all to practice some coding.

Challenge, My solutions

The etymology of this weeks title is the use of set in the Python solution, grep in the Perl solution, matching items in a list/array and a nod to the Wimbledon Grand Slam.

Task 1: Same Row Column

Task

You are given a n × n matrix containing integers from 1 to n.

Write a script to find if every row and every column contains all the integers from 1 to n.

My solution

For input from the command line, I take a JSON-fomatted string which is converted to a list (array in Perl) called matrix.

For the Python solution, I start by checking that the matrix is square.

def same_row_column(matrix: list[list[int]]) -> bool:
    length = len(matrix)
    for row in matrix:
        if len(row) != length:
            raise ValueError("All rows must have the same length")
Enter fullscreen mode Exit fullscreen mode

I then create a set of the expected values of each row and column.

    expected_set = set(range(1, length+1))
Enter fullscreen mode Exit fullscreen mode

Finally I check each row and each column meets the criteria. If it doesn't, I return False. If all checks pass, I return True. Sets are unordered so {1, 2, 3} is equal to {3, 2, 1}.

    for i in range(length):
        if set(matrix[i]) != expected_set:
            return False

        if set(matrix[r][i] for r in range(length)) != expected_set:
            return False

    return True
Enter fullscreen mode Exit fullscreen mode

Perl does not have sets, so the solution is slightly different. I start by creating a function called check_values. This checks that every value from 1 to n (the length of the matrix) is present. It will return 1 if it is, or 0 if it isn't.

use List::Util 'none';

sub check_values (@ints) {
    # Check that each number from 1 to the length of ints is present
    for my $i ( 1 .. $#ints + 1 ) {
        if ( none { $_ == $i } @ints ) {
            return 0;
        }
    }

    return 1;
}
Enter fullscreen mode Exit fullscreen mode

The rest of the code follows the same logic as the Python solution. It uses the map function to retrieve the columns as required.

sub main ($matrix_json) {
    my $matrix = decode_json($matrix_json);

    my $length = scalar(@$matrix);

    foreach my $row (@$matrix) {
        if ( scalar(@$row) != $length ) {
            die "All rows must have the same length\n";
        }
    }

    foreach my $i ( 0 .. $#$matrix ) {
        if ( not check_values( @{ $matrix->[$i] } ) ) {
            say 'false';
            return;
        }

        if ( not check_values( map { $_->[$i] } @$matrix ) ) {
            say 'false';
            return;
        }
    }

    say 'true';
}
Enter fullscreen mode Exit fullscreen mode

Examples

$ ./ch-1.py "[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]"
True

$ ./ch-1.py "[[1]]"
True

$ ./ch-1.py "[[1, 2, 5], [5, 1, 2], [2, 5, 1]]"
False

$ ./ch-1.py "[[1, 2, 3], [1, 2, 3], [1, 2, 3]]"
False

$ ./ch-1.py "[[1, 2, 3], [3, 1, 2], [3, 2, 1]]"
False
Enter fullscreen mode Exit fullscreen mode

Task 2: Smaller Greater Element

Task

You are given an array of integers.

Write a script to find the number of elements that have both a strictly smaller and greater element in the given array.

My solution

Unless I'm missing something obvious, this task is to count the number of items that aren't the lowest or higher number. For this task, I create a set of the lowest and highest number called excluded_values and then count the number items that aren't in the set.

def smaller_greater_element(ints: list[int]) -> int:
    excluded_values = {min(ints), max(ints)}
    return sum(1 for i in ints if i not in excluded_values)
Enter fullscreen mode Exit fullscreen mode

For the Perl solution, I create two variables min_value and max_value. I then use the grep function to count the number of items isn't one of the value. The function will return the number of items in the array if it is assigned to a scalar.

use List::Util qw(max min);

sub main (@ints) {
    my $min_value = min(@ints);
    my $max_value = max(@ints);

    my $count = grep { $_ != $min_value && $_ != $max_value } @ints;
    say $count;
}
Enter fullscreen mode Exit fullscreen mode

Examples

$ ./ch-2.py 2 4
0

$ ./ch-2.py 1 1 1 1
0

$ ./ch-2.py 1 1 4 8 12 12
2

$ ./ch-2.py 3 6 6 9
2

$ ./ch-2.py 0 -5 10 -2 4
3
Enter fullscreen mode Exit fullscreen mode

Top comments (0)