aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-172/walt-mankowski/README.md113
1 files changed, 79 insertions, 34 deletions
diff --git a/challenge-172/walt-mankowski/README.md b/challenge-172/walt-mankowski/README.md
index 7e4eff8dc2..ff4444732e 100644
--- a/challenge-172/walt-mankowski/README.md
+++ b/challenge-172/walt-mankowski/README.md
@@ -1,61 +1,106 @@
Solutions by Walt Mankowski.
-# Task #1: Abundant Odd Numbers
+# Task #1: Prime Partition
-For this task we need to find the first 20 odd **Abundant Numbers**. An [Abundant number](https://en.wikipedia.org/wiki/Abundant_number) is a number which is less than the sum of its proper divisors.
+For this task we're given 2 positive integers _m_ and _n_, and we need to find _n_ unique prime numbers that add up to _m_.
-I don't have much to say about this because it was quite simple to solve this by brute force. My only insight is to note that odd numbers can only have odd divisors, so we only have to check half the possible values.
+To solve this I made use of the `primes_to()` function I wrote for Challenge 169. I also used `Algorithm::Combinatorics` to find combinations of primes taking _n_ at time, and `sum()` from `List::Utils` to find the sum. Using those 3 functions this challenge was easy to solve:
```perl
-sub odd_divisors($n) {
- my @od = (1);
- my $max = $n / 2;
- for (my $i = 3; $i <= $max; $i += 2) {
- push @od, $i if $n % $i == 0;
- }
- return @od;
+$, = " ";
+my ($m, $n) = @ARGV;
+my $primes = primes_to($m);
+my $iter = combinations($primes, $n);
+while (my $p = $iter->next) {
+ say $p->@* if sum($p->@*) == $m;
}
```
-I also did a version in Python. In Python we can write `odd_divisors()` basically as a one-liner since `range()` lets us avoid a for loop:
+I also wrote a version in Python. First I needed to port `primes_to()` to Python:
```python
-def odd_divisors(n):
- od = [i for i in range(1,n//2+1,2) if n % i == 0]
- return od
+# find the primes up to n using the sieve of Eratosthenes and return
+# them as a list
+def primes_to(n):
+ is_prime = [True] * (n+1)
+ is_prime[0] = is_prime[1] = False
+ for i in range(2, int(sqrt(n))+1):
+ if is_prime[i]:
+ for j in range(i+i, n+1, i):
+ is_prime[j] = False
+
+ return [i for i,val in enumerate(is_prime) if val]
```
-# Task 2: First-class Function
+Then the actual code to solve the challenge ended up looking very similar to the Perl version:
-For this task we needed to create a function `compose(f,g)` that takes in two parameters `f` and `g` as subroutine references, and returns the subroutine `f(g(x))`.
+```python
+import sys
+from itertools import combinations
+from primes import primes_to
-I just wrote this as a very simple function in Perl:
+m, n = [int(x) for x in sys.argv[1:]]
+primes = primes_to(m)
-```perl
-sub compose($f, $g) {
- return sub { $f->($g->(@_)) };
-}
+for comb in combinations(primes, n):
+ if sum(comb) == m:
+ print(comb)
```
-Then I tested it by composing 2 functions, one which sums its arguments and another which doubles each of its arguments:
+# Task 2: Five-number Summary
+
+For this task we're given a list of numbers and need to compute their (Five-number Summary)[https://en.wikipedia.org/wiki/Five-number_summary], which consists of
+
+1. The minimum value
+2. The lower quartile
+3. The median
+4. The upper quartile
+5. The maximum value
+
+To solve this I first sorted the list. The minimum and maximum values are just the first and last element of the sorted list. Then I wrote a function to compute the median of a sorted list.
```perl
-sub sum {
- my $sum = 0;
- $sum += $_ for @_;
- return $sum;
+sub median_sorted(@a) {
+ my $len2 = int(@a / 2);
+ return @a % 2 == 1 ? $a[$len2] : ($a[$len2-1] + $a[$len2]) / 2;
}
+```
+Once we have that, then the lower quartile is the median of the values before the median in the sorted list, and the upper quartile is the median of the values after the median.
-sub double {
- return map { $_ * 2 } @_;
+```perl
+sub fivenum(@a) {
+ my @sorted = sort {$a <=> $b} @a;
+ my $min = $sorted[0];
+ my $max = $sorted[-1];
+ my $median = median_sorted(@sorted);
+
+ my $len2 = int(@sorted / 2);
+ my $lower = median_sorted(@sorted[0..$len2-1]);
+ my $upper;
+ if (@sorted % 2 == 1) { # odd number of elements
+ $upper = median_sorted(@sorted[$len2+1..$#sorted]);
+ } else {
+ $upper = median_sorted(@sorted[$len2..$#sorted]);
+ }
+ return ($min, $lower, $median, $upper, $max);
}
```
-Here's an example of using it. The output is `20`.
+`fivenum()` was a little tricky to port to Python. First, `sorted`, `min`, and `max` are all reserved words to Python, so I had to come up with different names for them. I decided to just prefix all the variable names with an underscore. I also had to be careful because the upper range of slices is inclusive in Perl but exclusive in Python. Here's my version:
-```perl
-my $c = compose(\&sum, \&double);
-say $c->(1,2,3,4);
+```python
+def fivenum(a):
+ _sorted = sorted(a)
+ _min = _sorted[0]
+ _max = _sorted[-1]
+ _median = median_sorted(_sorted)
+
+ len2 = len(a) // 2
+ _lower = median_sorted(_sorted[0:len2])
+ if len(a) % 2 == 1: # odd number of elements
+ _upper = median_sorted(_sorted[len2+1:])
+ else:
+ _upper = median_sorted(_sorted[len2:])
+
+ return _min, _lower, _median, _upper, _max
```
-
-I never got a version of this working in Python.