Perl Weekly Challenge 373‘s tasks are “Equal List” and “List Division”.
But if you insist on knowing my BLISS
I’ll tell you this
If you want to know what the Reason is
I only smile when I lie, then I’ll tell you why…
Because your kiss, your kiss is an equal list
Because your kiss, your kiss divides my list
Because your kiss is on my list of the best things in life
Task 1: Equal List
You are given two arrays of strings.
Write a script to return true if the two given array represent the same strings otherwise false.
Input: @arr1 = ("a", "bc")
@arr2 = ("ab", "c")
Output: true
Array 1: "a" + "bc" = "abc"
Array 2: "ab" + "c" = "abc"
Input: @arr1 = ("a", "b", "c")
@arr2 = ("a", "bc")
Output: true
Array 1: "a" + "b" + "c" = "abc"
Array 2: "a" + "bc" = "abc"
Input: @arr1 = ("a", "bc")
@arr2 = ("a", "c", "b")
Output: false
Array 1: "a" + "bc" = "abc"
Array 2: "a" + "c" + "b" = "acb"
Input: @arr1 = ("ab", "c", "")
@arr2 = ("", "a", "bc")
Output: true
Array 1: "ab" + "c" + "" = "abc"
Array 2: "" + "a" + "bc" = "abc"
Input: @arr1 = ("p", "e", "r", "l")
@arr2 = ("perl")
Output: true
Array 1: "p" + "e" + "r" + "l" = "perl"
Array 2: "perl"
Approach
This problem screams for a join. Yes, we could use other methods to concatenate strings together, but in all the languages I’m using, join accepts an array of arbitrary length, so I don’t have to account for how many entries there are in the array.
Raku
And in two of these languages, I don’t even need to pass a separator. In Raku, List.join defaults to the empty string as a separator.
sub equal_list(@arr1, @arr2) {
return @arr1.join eq @arr2.join;
}View the entire Raku script for this task on GitHub.
$ raku/ch-1.raku
Example 1:
Input: @arr1 = ("a", "bc")
@arr2 = ("ab", "c")
Output: True
Example 2:
Input: @arr1 = ("a", "b", "c")
@arr2 = ("a", "bc")
Output: True
Example 3:
Input: @arr1 = ("a", "bc")
@arr2 = ("a", "c", "b")
Output: False
Example 4:
Input: @arr1 = ("ab", "c", "")
@arr2 = ("", "a", "bc")
Output: True
Example 5:
Input: @arr1 = ("p", "e", "r", "l")
@arr2 = ("perl")
Output: TruePerl
Perl’s join, however does require a separator.
sub equal_list($arr1, $arr2) {
return join('', @$arr1) eq join('', @$arr2) ? 'true' : 'false';
}View the entire Perl script for this task on GitHub.
Python
In Python, .join is a method is a method off the string object acting as the separator.
def equal_list(arr1, arr2):
return ''.join(arr1) == ''.join(arr2)View the entire Python script for this task on GitHub.
Elixir
Elixir is the other language where Enum.join/2 doesn’t require a separator; if joiner is not passed at all, it defaults to an empty string.
def equal_list(arr1, arr2) do
Enum.join(arr1) == Enum.join(arr2)
endView the entire Elixir script for this task on GitHub.
Task 2: List Division
You are given a list and a non-negative integer.
Write a script to divide the given list into given non-negative integer equal parts. Return -1 if the integer is more than the size of the list.
Input: @list = (1,2,3,4,5), $n = 2
Output: ((1,2,3), (4,5))
5 / 2 = 2 remainder 1.
The extra element goes into the first chunk.
Input: @list = (1,2,3,4,5,6), $n = 3
Output: ((1,2), (3,4), (5,6))
6 / 3 = 2 remainder 0.
Input: @list = (1,2,3), $n = 2
Output: ((1,2), (3))
Input: @list = (1,2,3,4,5,6,7,8,9,10), $n = 5
Output: ((1,2), (3,4), (5,6), (7,8), (9,10))
Input: @list = (1,2,3), $n = 4
Output: -1
Input: @list = (72,57,89,55,36,84,10,95,99,35), $n = 7;
Output: ((72,57), (89,55), (36,84), (10), (95), (99), (35))
Approach
Really, the first example gives the approach away. We divide the length of the list by $n, and get back the integer result ($c) and the remainder ($r). We then start making lists of $c elements, adding an extra element to the first $r lists.
Python
Because last week in PWC 372’s first task, I discovered Python’s divmod, I’m doing the Python solution first.
def list_div(arr, n):
if len(arr) < n: return -1
c, r = divmod(len(arr), n)
result = []
while arr:
a = []
for i in range(0, c):
a.append(arr.pop(0))
if r: # we have a remainder to deal with
a.append(arr.pop(0))
r -= 1
result.append(a)
return resultView the entire Python script for this task on GitHub.
$ python/ch-2.py
Example 1:
Input: @list = (1, 2, 3, 4, 5), $n = 2
Output: ((1,2,3), (4,5))
Example 2:
Input: @list = (1, 2, 3, 4, 5, 6), $n = 3
Output: ((1,2), (3,4), (5,6))
Example 3:
Input: @list = (1, 2, 3), $n = 2
Output: ((1,2), (3))
Example 4:
Input: @list = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), $n = 5
Output: ((1,2), (3,4), (5,6), (7,8), (9,10))
Example 5:
Input: @list = (1, 2, 3), $n = 4
Output: -1
Example 5:
Input: @list = (72, 57, 89, 55, 36, 84, 10, 95, 99, 35), $n = 7
Output: ((72,57), (89,55), (36,84), (10), (95), (99), (35))Raku
And because I’m so enamored of divmod, I’m rolling my own in the other languages…
sub divmod($x, $y) { ($x div $y, $x % $y) }
sub list_div(@list, $n) {
return -1 if @list.elems < $n;
my ($c, $r) = divmod(@list.elems, $n);
my @result;
while @list {
my @a;
@a.push(@list.shift) for 1..$c;
@a.push(@list.shift) if --$r >= 0;
@result.push(@a);
}
@result;
}View the entire Raku script for this task on GitHub.
Perl
sub divmod($x, $y) { (int($x / $y), $x % $y) }
sub list_div($list, $n) {
return -1 if @$list < $n;
my ($c, $r) = divmod(scalar(@$list), $n);
my @result;
while (@$list) {
my @a;
push @a, shift(@$list) for 1..$c;
push @a, shift(@$list) if --$r >= 0;
push @result, \@a;
}
@result;
}View the entire Perl script for this task on GitHub.
Elixir
I rolled a bunch of custom functions in this solution:
divmod/2– like I did in each of the previous twoshift_first/3– takes the firstcelements in the providedlistand appends them toshifted. This made mode sense to me than trying to modify bothlistand a result array in an Enum.reduce/3.build_result/4– similarly, once we calculatedcandr, it would probably have been possible to do the looping with an Enum.reduce/3, but it made a lot more sense to build a recursive function to processlist.- I used a lot of guards and even a default value in a function head.
def divmod(x,y), do: { div(x,y), rem(x, y) }
def shift_first(list, c, shifted \\ [])
def shift_first(list, c, shifted) when c == 0, do:
{list, shifted}
def shift_first([e | rest], c, shifted) do
shift_first(rest, c-1, shifted ++ [e])
end
def build_result([], _, _, result), do: result
def build_result(list, c, r, result) do
{list, a} = shift_first(list, c)
{list, a} = if r > 0 do
shift_first(list, 1, a)
else
{list, a}
end
build_result(list, c, r-1, result ++ [a])
end
def list_div(list, n) when length(list) < n, do: -1
def list_div(list, n) do
{c, r} = divmod(length(list), n)
build_result(list, c, r, [])
endView the entire Elixir script for this task on GitHub.
Here’s all my solutions in GitHub: https://github.com/packy/perlweeklychallenge-club/tree/challenge-373-packy-anderson/challenge-373/packy-anderson