diff options
| author | irifkin <ianrifkin@ianrifkin.com> | 2023-11-26 10:05:36 -0500 |
|---|---|---|
| committer | irifkin <ianrifkin@ianrifkin.com> | 2023-11-26 10:05:36 -0500 |
| commit | 2cbcaebea8b7040874a054e50d578d312ab369a5 (patch) | |
| tree | e952a28e933b0721509937e916424ad9602a5728 | |
| parent | a21c8ec426c8151d3b00e2e7e17d220992bea80f (diff) | |
| download | perlweeklychallenge-club-2cbcaebea8b7040874a054e50d578d312ab369a5.tar.gz perlweeklychallenge-club-2cbcaebea8b7040874a054e50d578d312ab369a5.tar.bz2 perlweeklychallenge-club-2cbcaebea8b7040874a054e50d578d312ab369a5.zip | |
Perl solutions and a short blog post
| -rw-r--r-- | challenge-244/ianrifkin/README.md | 135 | ||||
| -rw-r--r-- | challenge-244/ianrifkin/blog.txt | 1 | ||||
| -rw-r--r-- | challenge-244/ianrifkin/perl/ch-1.pl | 111 | ||||
| -rw-r--r-- | challenge-244/ianrifkin/perl/ch-2.pl | 100 |
4 files changed, 268 insertions, 79 deletions
diff --git a/challenge-244/ianrifkin/README.md b/challenge-244/ianrifkin/README.md index 10bfcf4aa0..9e84586460 100644 --- a/challenge-244/ianrifkin/README.md +++ b/challenge-244/ianrifkin/README.md @@ -1,113 +1,90 @@ -# loop-de-loop +# And then a hero comes along -Challenge 243: https://theweeklychallenge.org/blog/perl-weekly-challenge-243/ +Challenge 244: https://theweeklychallenge.org/blog/perl-weekly-challenge-244/ -I decided to take what I think is a simple approcah to solving this week's problems (and I basically did the same approach in both tasks). +This task was during the week of American Thanksgiving so I may not be fully present with my responses. The first task seemed straightforward enough so let's start with that one. + +## Task 1: Count Smaller -## Task 1: Reverse Pairs ``` You are given an array of integers. -Write a script to return the number of reverse pairs in the given array. - -A reverse pair is a pair (i, j) where: a) 0 <= i < j < nums.length and b) nums[i] > 2 * nums[j]. +Write a script to calculate the number of integers smaller than the integer at each index. Example 1 -Input: @nums = (1, 3, 2, 3, 1) -Output: 2 - -(1, 4) => nums[1] = 3, nums[4] = 1, 3 > 2 * 1 -(3, 4) => nums[3] = 3, nums[4] = 1, 3 > 2 * 1 +Input: @int = (8, 1, 2, 2, 3) +Output: (4, 0, 1, 1, 3) + +For index = 0, count of elements less 8 is 4. +For index = 1, count of elements less 1 is 0. +For index = 2, count of elements less 2 is 1. +For index = 3, count of elements less 2 is 1. +For index = 4, count of elements less 3 is 3. Example 2 -Input: @nums = (2, 4, 3, 5, 1) -Output: 3 - -(1, 4) => nums[1] = 4, nums[4] = 1, 4 > 2 * 1 -(2, 4) => nums[2] = 3, nums[4] = 1, 3 > 2 * 1 -(3, 4) => nums[3] = 5, nums[4] = 1, 5 > 2 * 1 +Input: @int = (6, 5, 4, 8) +Output: (2, 1, 0, 3) +Example 3 +Input: @int = (2, 2, 2) +Output: (0, 0, 0) ``` -I added some extra code to my solutions in support of features like supporting command-line input, but let's focus on the code that actually solves the task. - -I pass the `@nums` array to a subroutine `reverse_pairs` which has a nested `for` loop in it. We want to count how many times `$nums[$i]` is `>` `$nums[$j] * 2` where `$j` is any item after `$i` in the array. Since there is no point to look at an `$i` with no `$j` the parent loop should contain every array element except the last one: - +I solve this by looping through the `@int` array and creating an array for the output for each numbers total of numbers that are smaller than it (defaulting it to 0): ``` -for (my $i = 0; $i < @nums-1; $i++) +for (my $i=0; $i < @int; $i++) { + $int_out[$i] = 0; #default is no number is smaller than it ``` -Within the above loop I created a nested loop to compare `$nums[$i]` to every value after it in the array. We know that `$j` is after `$i` so the loop can start at the element after `$i` and continues to the end of the array: +Then I loop through the `@int` array again, this time to check each number in the array (except for itself) and increment the output number when needed: ``` -for (my $j = $i+1; $j < @nums; $j++) +for (my $j=0; $j < @int; $j++) { + $int_out[$i]++ if ($int[$i] > $int[$j] && $i != $j); +} ``` -Within that loop I increment a counter whenever `$nums[$i] > $nums[$j] * 2` - -The full sub is as follows: +That's it! Other than that it's just calling the sub and outputting it in the desired format. -``` -sub reverse_pairs { - my @nums = @_; - my $pairs_found = 0; - for (my $i = 0; $i < @nums-1; $i++) { - for (my $j = $i+1; $j < @nums; $j++) { - $pairs_found++ if ($nums[$i] > $nums[$j] * 2); - } - } - return $pairs_found; -} -``` +## Task 2: Group Hero -## Task 2: Floor Sum ``` -You are given an array of positive integers (>=1). +You are given an array of integers representing the strength. -Write a script to return the sum of floor(nums[i] / nums[j]) where 0 <= i,j < nums.length. The floor() function returns the integer part of the division. +Write a script to return the sum of the powers of all possible combinations; power is defined as the square of the largest number in a sequence, multiplied by the smallest. Example 1 -Input: @nums = (2, 5, 9) -Output: 10 - -floor(2 / 5) = 0 -floor(2 / 9) = 0 -floor(5 / 9) = 0 -floor(2 / 2) = 1 -floor(5 / 5) = 1 -floor(9 / 9) = 1 -floor(5 / 2) = 2 -floor(9 / 2) = 4 -floor(9 / 5) = 1 -Example 2 -Input: @nums = (7, 7, 7, 7, 7, 7, 7) -Output: 49 -``` +Input: @nums = (2, 1, 4) +Output: 141 -My solution to this task is very similar to my approach to solving task 1. Again I start with a loop of every array item, but this time the parent loop does include the last element in the array: -``` -for (my $i = 0; $i < @nums; $i++) -``` +Group 1: (2) => square(max(2)) * min(2) => 4 * 2 => 8 +Group 2: (1) => square(max(1)) * min(1) => 1 * 1 => 1 +Group 3: (4) => square(max(4)) * min(4) => 16 * 4 => 64 +Group 4: (2,1) => square(max(2,1)) * min(2,1) => 4 * 1 => 4 +Group 5: (2,4) => square(max(2,4)) * min(2,4) => 16 * 2 => 32 +Group 6: (1,4) => square(max(1,4)) * min(1,4) => 16 * 1 => 16 +Group 7: (2,1,4) => square(max(2,1,4)) * min(2,1,4) => 16 * 1 => 16 -Likewise, the nested loop within it needs to include every element (including where `$i == $j`) so it's basically the same loop as its parent: -``` -for (my $j = 0; $j < @nums; $j++) +Sum: 8 + 1 + 64 + 4 + 32 + 16 + 16 => 141 ``` -Within that loop I take the floor of `$nums[$i] / $nums[$j]` and add it to the sum of the previous values. To calculate the floor I was going to use the actual `floor()` from `POSIX` but just used `int()` -- I think it's good enough for this task but note that `int()` can sometimes produce counterintuitive results (see https://perldoc.perl.org/functions/int). +This task was a lot more challenging for me and I'm not entirely sure I am solving it in a sane manner, but I do appear to get the correct output. -The full sub is as follows: +I created a subroutine `group_hero` which accepts the input array. I then use `Algorithm::Combinatorics qw(partitions)` to create the different number combinations. Is this cheating? Maybe, but I'm okay with it. Don't worry, it's not the only "cheat" I used in this one. I also use `List::Util qw( min max )` to calculuate the min and max values in an array! +So I start byt creating the number combinations: `my @parts = partitions(\@nums);` + +The final array element in `@parts` is duplicative for our purposes so I ignore that. I loop through the rest of the parts: `for (my $i=0; $i<@parts-1; $i++) {` + +Each `$parts[$i]` is an array of the desired combinations so I loop through that: `foreach ( @{$parts[$i]} ) {` + +Within this final loop I calculate the min, max and perform the math: ``` -sub sum_floors { - my @nums = @_; - my $sum_floors = 0; - for (my $i = 0; $i < @nums; $i++) { - for (my $j = 0; $j < @nums; $j++) { - $sum_floors += int($nums[$i] / $nums[$j]); - } - } - return $sum_floors; -} +my $min = min @{$parts[0]}; +my $max = max @{$parts[0]}; +$group_hero += $max**2 * $min; ``` -The full code with comments is available at https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-243/ianrifkin
\ No newline at end of file +Then at the conclusion I return `$group_hero` with the final number. + +--- +The full code with comments is available at https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-244/ianrifkin diff --git a/challenge-244/ianrifkin/blog.txt b/challenge-244/ianrifkin/blog.txt new file mode 100644 index 0000000000..39bffa2018 --- /dev/null +++ b/challenge-244/ianrifkin/blog.txt @@ -0,0 +1 @@ +https://github.com/manwar/perlweeklychallenge-club/tree/master/challenge-244/ianrifkin#readme diff --git a/challenge-244/ianrifkin/perl/ch-1.pl b/challenge-244/ianrifkin/perl/ch-1.pl new file mode 100644 index 0000000000..b41e0c1ae1 --- /dev/null +++ b/challenge-244/ianrifkin/perl/ch-1.pl @@ -0,0 +1,111 @@ +use v5.30.3; +use warnings; +use strict; +use Getopt::Long; +use Pod::Usage; +use Data::Dumper; + +# Task 1: Count Smaller + +my $man = 0; +my $help = 0; +my $str_input; +GetOptions ('help|?' => \$help, man => \$man, + "nums=s" => \$str_input + ) + or pod2usage(2); + +pod2usage(1) if $help; +pod2usage(-exitstatus => 0, -verbose => 2) if $man; + +# Prepare input array +my @int; +# if values provided at cmd line split on comma +if ( $str_input ) { + say reverse_pairs(split(/,/, $str_input)); +} +# else set default values from example if no cmd line input +else { + # Example 1 + @int = (8, 1, 2, 2, 3); + say count_smaller(@int); + + # Example 2 + @int = (6, 5, 4, 8); + say count_smaller(@int); + + # Example 3 + @int = (2, 2, 2); + say count_smaller(@int); +} + +sub count_smaller { + my @int = @_; + my @int_out; + + # Loop through each number in array to count how many numbers are smaller than it + for (my $i=0; $i < @int; $i++) { + $int_out[$i] = 0; #default is no number is smaller than it + # check each number in the array except for self + for (my $j=0; $j < @int; $j++) { + $int_out[$i]++ if ($int[$i] > $int[$j] && $i != $j); + } + } + + # 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(@int_out)) . ')'; +} + +__END__ + +=head1 Challenge 244, Task 1: Count Smaller, by IanRifkin + +You are given an array of integers. + +Write a script to calculate the number of integers smaller than the integer at each index. + +Example 1 +Input: @int = (8, 1, 2, 2, 3) +Output: (4, 0, 1, 1, 3) + +For index = 0, count of elements less 8 is 4. +For index = 1, count of elements less 1 is 0. +For index = 2, count of elements less 2 is 1. +For index = 3, count of elements less 2 is 1. +For index = 4, count of elements less 3 is 3. +Example 2 +Input: @int = (6, 5, 4, 8) +Output: (2, 1, 0, 3) +Example 3 +Input: @int = (2, 2, 2) +Output: (0, 0, 0) + +See https://theweeklychallenge.org/blog/perl-weekly-challenge-244/#TASK1 for more information on this challenge + +=head1 SYNOPSIS + +perl ./ch-1.pl [options] + +=head1 OPTIONS + +=over 8 + +=item B<-nums> + +A list of numbers + +=item B<-help> + +Print a brief help message and exits. + +=item B<-man> + +Prints the manual page and exits. + +=back + + + + diff --git a/challenge-244/ianrifkin/perl/ch-2.pl b/challenge-244/ianrifkin/perl/ch-2.pl new file mode 100644 index 0000000000..e15f62303b --- /dev/null +++ b/challenge-244/ianrifkin/perl/ch-2.pl @@ -0,0 +1,100 @@ +use v5.30.3; +use warnings; +use strict; +use Getopt::Long; +use Pod::Usage; +use Algorithm::Combinatorics qw(partitions); +use List::Util qw( min max ); +use Data::Dumper; + +# Task 2: Group Hero + +my $man = 0; +my $help = 0; +my $str_input; +GetOptions ('help|?' => \$help, man => \$man, + "nums=s" => \$str_input + ) + or pod2usage(2); + +pod2usage(1) if $help; +pod2usage(-exitstatus => 0, -verbose => 2) if $man; + +# Prepare input array +my @nums; +# if values provided at cmd line split on comma +if ( $str_input ) { + say reverse_pairs(split(/,/, $str_input)); +} +# else set default values from example if no cmd line input +else { + # Example 1 + @nums = (2, 1, 4); + say group_hero(@nums); +} + +sub group_hero { + my @nums = @_; + my $group_hero = 0; + + my @parts = partitions(\@nums); + for (my $i=0; $i<@parts-1; $i++) { + foreach ( @{$parts[$i]} ) { + my @parts = $_; + my $min = min @{$parts[0]}; + my $max = max @{$parts[0]}; + $group_hero += $max**2 * $min; + } + } + return $group_hero; +} + +__END__ + +=head1 Challenge 244, Task 2: Count Smaller, by IanRifkin + +You are given an array of integers representing the strength. + +Write a script to return the sum of the powers of all possible combinations; power is defined as the square of the largest number in a sequence, multiplied by the smallest. + +Example 1 +Input: @nums = (2, 1, 4) +Output: 141 + +Group 1: (2) => square(max(2)) * min(2) => 4 * 2 => 8 +Group 2: (1) => square(max(1)) * min(1) => 1 * 1 => 1 +Group 3: (4) => square(max(4)) * min(4) => 16 * 4 => 64 +Group 4: (2,1) => square(max(2,1)) * min(2,1) => 4 * 1 => 4 +Group 5: (2,4) => square(max(2,4)) * min(2,4) => 16 * 2 => 32 +Group 6: (1,4) => square(max(1,4)) * min(1,4) => 16 * 1 => 16 +Group 7: (2,1,4) => square(max(2,1,4)) * min(2,1,4) => 16 * 1 => 16 + +Sum: 8 + 1 + 64 + 4 + 32 + 16 + 16 => 141 + +See https://theweeklychallenge.org/blog/perl-weekly-challenge-244/#TASK2 for more information on this challenge + +=head1 SYNOPSIS + +perl ./ch-1.pl [options] + +=head1 OPTIONS + +=over 8 + +=item B<-nums> + +A list of numbers + +=item B<-help> + +Print a brief help message and exits. + +=item B<-man> + +Prints the manual page and exits. + +=back + + + + |
