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.
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
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)
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)
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 );
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
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
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)
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
Top comments (0)