DEV Community

Simon Green
Simon Green

Posted on

Weekly Challenge: Compare the Average

Weekly Challenge 321

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. It's a great way for us all to practice some coding.

Challenge, My solutions

Task 1: Distinct Average

Task

You are given an array of numbers with even length.

Write a script to return the count of distinct average. The average is calculate by removing the minimum and the maximum, then average of the two.

My solution

The first thing to observe is this task mentions numbers, and not integers. And it's a well known fact that the average of 0.2 and 0.4 is not 0.3

>>> (0.2 + 0.4) / 2
0.30000000000000004
Enter fullscreen mode Exit fullscreen mode

To mitigate this, I use the decimal module in Python, and the bignum module in Perl. Both of these will handle non-integer numbers as a human would expect.

For the Python solution, I start by checking that we have an even number of items in the numbers list. I then sort the list numerically, converting the numbers into the decimal type.

def distinct_average(numbers: list) -> int:
    unique_averages = set()

    if len(numbers) % 2 == 1:
        raise ValueError("You must provide an even number of numbers")

    numbers = sorted(Decimal(i) for i in numbers)
Enter fullscreen mode Exit fullscreen mode

I then have a loop with the variable idx from 0 to one less than half the length of the list. For each iteration, I take the number from that position and the opposite position from the end and add half the sum of them to the unique_averages set. As a set only contains unique values, any duplicates won't be recorded.

I end by returning the number of items in the set.

    for idx in range(len(numbers)//2):
        unique_averages.add((numbers[idx] + numbers[-1-idx])/2)

    return len(unique_averages)
Enter fullscreen mode Exit fullscreen mode

Perl doesn't have an equivalent of sets, although the keys of hashes can serve this purpose. My Perl solution records all the averages, and then returns the number of unique values.

    foreach my $idx ( 0 .. scalar(@numbers) / 2 - 1) {
        push( @averages, ( $numbers[$idx] + $numbers[ $#numbers - $idx ] ) / 2 );
    }

    say scalar( uniq @averages );
Enter fullscreen mode Exit fullscreen mode

Examples

$ ./ch-1.py 1 2 3 4 5 6
1

$ ./ch-1.py 0 2 4 8 3 5
2

$ ./ch-1.py 7 3 1 0 5 9
2
Enter fullscreen mode Exit fullscreen mode

Task 2: Backspace Compare

Task

You are given two strings containing zero or more #.

Write a script to return true if the two given strings are same by treating # as backspace.

My solution

There are at least two ways to tackle this solution, each with pros and cons. One solution would involve regular expressions, but I'm not convinced that this is more beneficial, for either speed or readability.

The solution I took was to create a function called convert_string. This takes a string with the variable s. It then loops over each letter with the variable c. If the character is #, I remove the last letter from the new_string array. This does not raise an error if new_string is empty. Any other character is appended to the new_string value.

def covert_string(s: str) -> str:
    new_string = ''
    for c in s:
        if c == '#':
            new_string = new_string[:-1]
        else:
            new_string += c

    return new_string
Enter fullscreen mode Exit fullscreen mode

Then it is a one liner to compare the two provided strings.

def backspace_compare(str1: str, str2: str) -> bool:
    return covert_string(str1) == covert_string(str2)
Enter fullscreen mode Exit fullscreen mode

The Perl solutions follows the same logic, with a slightly different syntax. It uses the chop function with removes the last character from a string. It is also safe when the new_string is already empty.

Examples

$ ./ch-2.py "ab#c" "ad#c"
True

$ ./ch-2.py "ab##" "a#b#"
True

$ ./ch-2.py "a#b" c
False
Enter fullscreen mode Exit fullscreen mode

Top comments (0)