aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2023-11-12 18:02:08 +0000
committerGitHub <noreply@github.com>2023-11-12 18:02:08 +0000
commitd14538f41564d292c7c1a44299cb8562e846a994 (patch)
tree865faaa73217cfe7f5949c26dbb6067cbe1b4a62
parent6526fb7a0d08959eb1b17d5deb966b9d2ddb67ec (diff)
parent4d132885b421c95decf38f5691fb9b8c78e859b4 (diff)
downloadperlweeklychallenge-club-d14538f41564d292c7c1a44299cb8562e846a994.tar.gz
perlweeklychallenge-club-d14538f41564d292c7c1a44299cb8562e846a994.tar.bz2
perlweeklychallenge-club-d14538f41564d292c7c1a44299cb8562e846a994.zip
Merge pull request #9035 from ianrifkin/ianrifkin-challenge-242
Ianrifkin challenge 242
-rw-r--r--challenge-242/ianrifkin/README.md181
-rw-r--r--challenge-242/ianrifkin/blog.txt1
-rw-r--r--challenge-242/ianrifkin/perl/ch-1.pl98
-rw-r--r--challenge-242/ianrifkin/perl/ch-2.pl70
4 files changed, 255 insertions, 95 deletions
diff --git a/challenge-242/ianrifkin/README.md b/challenge-242/ianrifkin/README.md
index ece05ca910..a519c9fd16 100644
--- a/challenge-242/ianrifkin/README.md
+++ b/challenge-242/ianrifkin/README.md
@@ -1,140 +1,131 @@
-# Math is hard?
+# I'm a Map
-Challenge 241: https://theweeklychallenge.org/blog/perl-weekly-challenge-241/
+Challenge 242: https://theweeklychallenge.org/blog/perl-weekly-challenge-242/
-Some of The Weekly Challenges are more intimidating for me based on how math-heavy the task feels. The first task seemed overwhelming but was pretty quick to create a solution, yet the second task took me much longer.
-
-## Task 1: Arithmetic Triplets
+This week's challenge is pretty fun because it's one of those types of problems that seems really easy but you can end up spending a bunch of time trying to figure out how to solve it in a way that makes some sense.
+## Task 1: Missing Members
```
-You are given an array (3 or more members) of integers in increasing order and a positive integer.
+You are given two arrays of integers.
-Write a script to find out the number of unique Arithmetic Triplets satisfying the following rules:
+Write a script to find out the missing members in each other arrays.
-a) i < j < k
-b) nums[j] - nums[i] == diff
-c) nums[k] - nums[j] == diff
Example 1
-Input: @nums = (0, 1, 4, 6, 7, 10)
- $diff = 3
-Output: 2
+Input: @arr1 = (1, 2, 3)
+ @arr2 = (2, 4, 6)
+Output: ([1, 3], [4, 6])
-Index (1, 2, 4) is an arithmetic triplet because both 7 - 4 == 3 and 4 - 1 == 3.
-Index (2, 4, 5) is an arithmetic triplet because both 10 - 7 == 3 and 7 - 4 == 3.
+(1, 2, 3) has 2 members (1, 3) missing in the array (2, 4, 6).
+(2, 4, 6) has 2 members (4, 6) missing in the array (1, 2, 3).
Example 2
-Input: @nums = (4, 5, 6, 7, 8, 9)
- $diff = 2
-Output: 2
+Input: @arr1 = (1, 2, 3, 3)
+ @arr2 = (1, 1, 2, 2)
+Output: ([3])
-(0, 2, 4) is an arithmetic triplet because both 8 - 6 == 2 and 6 - 4 == 2.
-(1, 3, 5) is an arithmetic triplet because both 9 - 7 == 2 and 7 - 5 == 2.
+(1, 2, 3, 3) has 2 members (3, 3) missing in the array (1, 1, 2, 2). Since they are same, keep just one.
+(1, 1, 2, 2) has 0 member missing in the array (1, 2, 3, 3).
```
-A quick read of this task was overwhelming to me because it sounded like it was going to be more math than I could handle, but upon closer inspection the answer is in the description.
-
-I kept it simple and just explicitely created the three loops with the three specified iterators. It's very helpful to match the incrementor names in my code with the task's description.
+My command-line knowledge makes me think of just having two files and `diff`'ing them. If I needed to solve this for a real purpose I would probably look to using List::Compare to get it done. But for the challenges I like to think about how else I could go about solving for it.
-I started by looping through the input array with an incrementer `$i`. We know that `$i` is needed for the first value so the max `$i` is going to be 2 less than the total array length: `for (my $i = 0; $i < $nums_length - 2; $i++)`
+When I first started writing code I tried to:
+1) create an hash for each array
+2) create an array using the hash to grep values in the other array
+3) process the output array to de-duplicate
+4) parse the de-duped output array for pretty printing
-Within this loop I just make the next loop with `$j` which is 1 more than `$i` to 1 less than the array length: `for (my $j = $i + 1; $j < $nums_length - 1; $j++)`
+It worked but it felt messy. Taking a step back to refactor I realized that I could create an array of hashes for the output, very succicintly:
-Finally within that loop I create the loop with `$k` which is going to be 1 more than `$j` to the end of the array: `for (my $k = $j + 1; $k < $nums_length; $k++)`
+```
+my @result_hashes = (
+ {map { $_ => check_if_exists($_, $arr2) } @{$arr1}},
+ {map { $_ => check_if_exists($_, $arr1) } @{$arr2}}
+ );
+```
-Now that I have my loops I go back to the instructions which stated:
+This sets each hash's key to the the value from the array. Then `check_if_exists` just `grep`s the other array for the value and returns true or false:
```
-nums[j] - nums[i] == diff
-and
-nums[k] - nums[j] == diff
+sub check_if_exists {
+ my ($k, $arr) = @_;
+ return 1 if grep /$k/, @{$arr};
+ return 0;
+}
```
-which in my Perl code is literally that same thing: `$nums[$j] - $nums[$i] == $diff && $nums[$k] - $nums[$j] == $diff`
-Anytime the above is true it increments a counter `$total_finds`. After the loops are complete it prints the `$total_finds` counter.
+That's it! Since the `@result_hashes` array contains hashes it is de-duped by naturely. The only remaining step is printing. Interestingly I expended more lines of code to get the printing in the desired format.
-The complete `sub find_triplets` is as follows:
+Parse hashed results into an @output array where the output array will end up having two values (one for each input).
+I loop through the array of hashed results putting the key from the hash in an array if the hash key's value is false (meaning the number was not found in the other array):
```
-sub find_triplets {
- my ($diff, $nums) = @_;
- my $nums_length = scalar @{$nums};
- my $total_finds = 0;
- for (my $i = 0; $i < $nums_length - 2; $i++) {
- for (my $j = $i + 1; $j < $nums_length - 1; $j++) {
- for (my $k = $j + 1; $k < $nums_length; $k++) {
- if (@{$nums}[$j] - @{$nums}[$i] eq $diff && @{$nums}[$k] - @{$nums}[$j] eq $diff) {
- $total_finds++;
- }
- }
+foreach (@result_hashes) {
+ my %h = %{$_};
+ my @tmp_out = ();
+
+ foreach my $key ( keys %h ) {
+ push(@tmp_out, $key) unless $h{$key};
}
- }
- print "$total_finds\n";
-}
```
-
-Full script with comments available at https://github.com/ianrifkin/perlweeklychallenge-club/blob/ianrifkin-challenge-241/challenge-241/ianrifkin/perl/ch-1.pl
-
-
-## Task 2: Prime Order
+Then I put that output into the @output array. Note that that point of having the @tmp_out step is solely to have separation between the two inputs. e.g. I want the output from example 1 to be `(['3','1'],['4','6'])` and not `('3','1','4','6')`:
+```
+push(@output, \@tmp_out) if @tmp_out;
```
-You are given an array of unique positive integers greater than 2.
-Write a script to sort them in ascending order of the count of their prime factors, tie-breaking by ascending value.
+For the final step (and not to make this any longer) I used `Data::Dumper` to return the `@output` array in the desired format:
+```
+$Data::Dumper::Terse = 1; #don't print VAR names
+$Data::Dumper::Indent = 0; #keep output on one line
+return '(' . join(',', Dumper(@output)) . ')';
+```
-Example 1
-Input: @int = (11, 8, 27, 4)
-Output: (11, 4, 8, 27))
+## Task 2: Flip Matrix
-Prime factors of 11 => 11
-Prime factors of 4 => 2, 2
-Prime factors of 8 => 2, 2, 2
-Prime factors of 27 => 3, 3, 3
```
+You are given n x n binary matrix.
-This one sounded simple enough but I needed to write WAY more code to accomplish. Though to be fair, part of the length is a lot more code comments and documentation -- critial because this quickly got confusing for me! After I completed it and it was working, I wasn't happy with how long the code got and how I was handling the looping so I refactored it a bit. The main different is the first attempt I really started by trying to find the prime factors and then counting them up. This was useful because it allowed me to check as I went along to make sure I was counting the right things appropriately. But once I got a good sense of it I realized it could be done quicker -- though mostly it's to reduce what felt like messy extra loops in code.
+Write a script to flip the given matrix as below.
-I split up the work into 2 subroutines.
+1 1 0
+0 1 1
+0 0 1
+a) Reverse each row
-The main sub, `prime_order()`, accepts an array of integers. It loops through the array to create a hash where the key is the input number from the array and the value is number of prime factors for that number. It generates the count of prime factors by calling a sub `prime_finder()`.
+0 1 1
+1 1 0
+1 0 0
-```prime_finder```
+b) Invert each member
-After the loop is complete `prime_order()` will create and print a sorted array based on the hash results.
-```
- foreach my $ordered_num (sort { $results{$a} <=> $results{$b} or $a <=> $b } keys %results) {
- push(@sorted_output, $ordered_num);
- }
+1 0 0
+0 0 1
+0 1 1
- # Finally, print the sorted output
- say "(" . join(", ", @sorted_output) . ")";
+Example 1
+Input: @matrix = ([1, 1, 0], [1, 0, 1], [0, 0, 0])
+Output: ([1, 0, 0], [0, 1, 0], [1, 1, 1])
+Example 2
+Input: @matrix = ([1, 1, 0, 0], [1, 0, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0])
+Output: ([1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 1], [1, 0, 1, 0])
```
-The sub `prime_finder()` is what actually cacluates the number of prime factors for a given input number.
-
+This was a fun task becasuse it's really simple to just look at the examples to know the output (especially with short array lenghts). Reversing numbers and flipping 0's and 1's is easy to do in your head. But how to do it in code? It ends up that it doesn't have to be very tricky either.
-I start by having a while loop set to repeat endlessly with a manual condition flag. This will be important based on my approach.
-
-Within the while loop I have a for loop that will find the biggest prime factor for a given number. The loop starts at the square root of the number `$i = int(sqrt($num))` and checks if a prime is found by seeing if dividing the number by the iterator has a remainder: `if ($num % $i == 0)`
-
-Some examples:
-
-input is 11 --> int of square root is 3 --> first prime factor found is 1 (meaning 11 is a prime number). In this case it increments the counter by 1 then exits the parent while loop.
-
-input is 27 --> int of square root is 5 --> first prime factor found is 3. The counter gets incremented to 1. To determine how many other prime factors it would take, I set the `$num` variable to `27 / 3` which is 9 and I exit the `for` loop, restarting it with the new `$num`. In this next iteration the prime found is 3. I increment the counter. Then it goes one more time where it determines that 3 is a prime number and does the final increment.
+I solved this task by passing the matrix array to a sub `matrix_flip` which just uses Perl's native `reverse` to put the array in backwards order then a simple conditional `map` that sets 1's to 0 and 0's to 1. Other than that is just some parentheses and commas for output readability.
```
- while ($calculating) {
- for (my $i = int(sqrt($num)); $i >= 1; $i--) {
- #looping backwards to find biggest prime factor first
- if ($num % $i == 0) { #if prime factor found
- $counter++; #increment that we found a prime factor
- $calculating = 0 if ($i == 1); #if the prime factor is 1 stop the parent while loop
- $num = $num / $i; #otherwise reset num lower to search for the next prime factor
- last; #and restart for loop with new number
- }
-
- }
+sub matrix_flip {
+ my @matrix_rows = @_;
+ my @new_matrix = ();
+
+ foreach my $row (@matrix_rows) {
+ #the actual flipping - use reverse to swap order and the map to flip values
+ my @new_row = '[' . join (", ", reverse map {$_ == 0 ? 1 : 0} @{$row}) . ']';
+ push (@new_matrix, @new_row);
}
+ return '(' . join (", ", @new_matrix) . ')';
+}
```
-The full code with comments is available at https://github.com/ianrifkin/perlweeklychallenge-club/blob/ianrifkin-challenge-241/challenge-241/ianrifkin/perl/ch-2.pl \ No newline at end of file
+The full code with comments is available at https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-242/ianrifkin \ No newline at end of file
diff --git a/challenge-242/ianrifkin/blog.txt b/challenge-242/ianrifkin/blog.txt
new file mode 100644
index 0000000000..7e5837dddf
--- /dev/null
+++ b/challenge-242/ianrifkin/blog.txt
@@ -0,0 +1 @@
+https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-242/ianrifkin#readme
diff --git a/challenge-242/ianrifkin/perl/ch-1.pl b/challenge-242/ianrifkin/perl/ch-1.pl
new file mode 100644
index 0000000000..91f34050d8
--- /dev/null
+++ b/challenge-242/ianrifkin/perl/ch-1.pl
@@ -0,0 +1,98 @@
+use v5.30.3;
+use warnings;
+use strict;
+use Getopt::Long;
+use Pod::Usage;
+use Data::Dumper;
+
+# You are given two arrays of integers.
+# Write a script to find out the missing members in each other arrays.
+
+my $man = 0;
+my $help = 0;
+GetOptions ('help|?' => \$help, man => \$man)
+ or pod2usage(2);
+
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+# Example 1
+my @arr1 = (1, 2, 3);
+my @arr2 = (2, 4, 6);
+say find_members(\@arr1, \@arr2);
+
+#Example 2
+@arr1 = (1, 2, 3, 3);
+@arr2 = (1, 1, 2, 2);
+say find_members(\@arr1, \@arr2);
+
+sub find_members {
+ my ($arr1, $arr2) = @_;
+
+ my @result_hashes = (
+ {map { $_ => check_if_exists($_, $arr2) } @{$arr1}},
+ {map { $_ => check_if_exists($_, $arr1) } @{$arr2}}
+ );
+
+ # Parse hashed results into an @output array
+ # output array will have two values (one for each input)
+ my @output = ();
+ foreach (@result_hashes) {
+ my %h = %{$_};
+ my @tmp_out = ();
+ # Select the hash key if the value is false
+ # --meaning that the number did not exist in the other array
+ foreach my $key ( keys %h ) {
+ push(@tmp_out, $key) unless $h{$key};
+ }
+ # The step of putting \@tmp_out into @output
+ # -- is so we have separation from results of
+ # -- the two inputs
+ push(@output, \@tmp_out) if @tmp_out;
+ }
+
+ # Return the @output array in the desired format
+ $Data::Dumper::Terse = 1; #don't print VAR names
+ $Data::Dumper::Indent = 0; #keep output on one line
+ return '(' . join(',', Dumper(@output)) . ')';
+}
+
+sub check_if_exists {
+ my ($k, $arr) = @_;
+ return 1 if grep /$k/, @{$arr};
+ return 0;
+}
+
+__END__
+
+=head1 Challenge 242, Task 1, by IanRifkin: Missing Members
+
+Given an input of two arrays, this script will find the missing members from each input array.
+
+Example 1 inputs: (1, 2, 3) and (2, 4, 6)
+
+Example 2 inputs: (1, 2, 3, 3) and (1, 1, 2, 2)
+
+See https://theweeklychallenge.org/blog/perl-weekly-challenge-241/#TASK1 for more information on this challenge
+
+=head1 SYNOPSIS
+
+perl ./ch-1.pl
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-help>
+
+Print a brief help message and exits.
+
+=item B<-man>
+
+Prints the manual page and exits.
+
+=back
+
+
+
+
diff --git a/challenge-242/ianrifkin/perl/ch-2.pl b/challenge-242/ianrifkin/perl/ch-2.pl
new file mode 100644
index 0000000000..be6601d695
--- /dev/null
+++ b/challenge-242/ianrifkin/perl/ch-2.pl
@@ -0,0 +1,70 @@
+use v5.30.3;
+use warnings;
+use strict;
+
+use Getopt::Long;
+use Pod::Usage;
+
+# You are given two arrays of integers.
+# Write a script to find out the missing members in each other arrays.
+
+my $man = 0;
+my $help = 0;
+GetOptions ('help|?' => \$help, man => \$man)
+ or pod2usage(2);
+
+pod2usage(1) if $help;
+pod2usage(-exitstatus => 0, -verbose => 2) if $man;
+
+
+# Example 1
+my @matrix = ([1, 1, 0], [1, 0, 1], [0, 0, 0]);
+say matrix_flip(@matrix);
+
+# Example 2
+@matrix = ([1, 1, 0, 0], [1, 0, 0, 1], [0, 1, 1, 1], [1, 0, 1, 0]);
+say matrix_flip(@matrix);
+
+sub matrix_flip {
+ my @matrix_rows = @_;
+ my @new_matrix = ();
+
+ foreach my $row (@matrix_rows) {
+ #the actual flipping - use reverse to swap order and the map to flip values
+ my @new_row = '[' . join (", ", reverse map {$_ == 0 ? 1 : 0} @{$row}) . ']';
+ push (@new_matrix, @new_row);
+ }
+ return '(' . join (", ", @new_matrix) . ')';
+}
+
+
+__END__
+
+=head1 Challenge 242, Task 2, by IanRifkin: Flip Matrix
+
+Given a "n x n" binary matrix, this script will flip the given matrix by revering each row then inverting each member.
+
+See https://theweeklychallenge.org/blog/perl-weekly-challenge-241/#TASK2 for more information on this challenge
+
+=head1 SYNOPSIS
+
+perl ./ch-2.pl
+
+=head1 OPTIONS
+
+=over 8
+
+=item B<-help>
+
+Print a brief help message and exits.
+
+=item B<-man>
+
+Prints the manual page and exits.
+
+=back
+
+
+
+
+