aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Smith <baggy@baggy.me.uk>2021-10-19 17:10:32 +0100
committerGitHub <noreply@github.com>2021-10-19 17:10:32 +0100
commitbb11efe8163a07c07c4c53edd0d82c6096bfeb90 (patch)
treede7b387d1d560ccc03b235ad030b618772a1e178
parent0f5a34b1abdb36741fe2840f2d787d3efe587bd9 (diff)
downloadperlweeklychallenge-club-bb11efe8163a07c07c4c53edd0d82c6096bfeb90.tar.gz
perlweeklychallenge-club-bb11efe8163a07c07c4c53edd0d82c6096bfeb90.tar.bz2
perlweeklychallenge-club-bb11efe8163a07c07c4c53edd0d82c6096bfeb90.zip
Update README.md
-rw-r--r--challenge-135/james-smith/README.md95
1 files changed, 62 insertions, 33 deletions
diff --git a/challenge-135/james-smith/README.md b/challenge-135/james-smith/README.md
index 1d17e5726f..dbb2c8cdca 100644
--- a/challenge-135/james-smith/README.md
+++ b/challenge-135/james-smith/README.md
@@ -1,4 +1,4 @@
-# Perl Weekly Challenge #134
+# Perl Weekly Challenge #135
You can find more information about this weeks, and previous weeks challenges at:
@@ -10,57 +10,86 @@ submit solutions in whichever language you feel comfortable with.
You can find the solutions here on github at:
-https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-134/james-smith/perl
+https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-135/james-smith/perl
-# Task 1 - Pandigital Numbers
+# Task 1 - Middle three digits
-***Write a script to generate first 5 Pandigital Numbers in base 10.***
+***You are given an integer. Write a script find out the middle 3-digits of the given integer, if possible otherwise throw sensible error.***
## The solution
-Pandigital numbers (base 10) are numbers who contain all the digits between 0-9 (but don't start with 0)
-The lowest pandigital numbers all are permutations of the digits 0..9 with 0 not being the first digit.
+Obviously using `substr $n, ??, 3` will give a 3-digit chunk of a number - so what are the errors...
-To walk the pandigital numbers we can write a script which generates the next perumtation in "lexical" order. You don't need to do this recursively or with tightly nested loops a simple algorithm finds them...
+ * Not an integer - doesn't match `/^-?\d+$/`
+ * Less than 3 digits - length less than 3
+ * Does not have a unique "central 3-digits" *i.e.* has even length
- * Find the largest value of `$i` such that `$s[$i]` `<` `$s[$i+1]`
- * Find the largest value of `$j` such that `$s[$i]` `<` `$s[$j]`
- * Flip these to entries
- * Flip all entries from $i+1 to end of the list...
+The value of the `??` is the expression above - `( length number - 3 ) / 2`
-We note though that we don't have to start at 0123456789 (the lowest permutation) as all numbers starting with 0 are skipped. We can then pre-empty this loop by noting the largest permutation 0987654321 which isn't a pan-digital number, so when we find the next iteration we have our first pandigital number....
+All that gives us the simple function....
```perl
-my @s = reverse 1..9, 0;
-
-sub next_perm {
- my( $i, $j );
- ( $s[$_] < $s[$_+1] ) && ( $i = $_ ) foreach 0 .. @s-2;
- return unless defined $i;
- ( $s[$i] < $s[$_] ) && ( $j = $_ ) foreach $i+1 .. @s-1;
- @s[ $i, $j ] = @s[ $j, $i ];
- @s[ $i+1 .. @s-1 ] = @s[ reverse $i+1 .. @s-1 ];
- return 1;
+sub middle3 {
+ my $n = shift;
+ return 'Not a number' unless $n =~ m{^-?\d+$};
+ my $l = length( $n = abs $n );
+ return $l < 3 ? 'Too short'
+ : $l % 2 ? substr $n, ( $l - 3 ) / 2, 3
+ : 'Even digits'
+ ;
}
+```
+
+It is possible to compact this slightly - buy 1 - assuming `$n` is an integer, and then rewriting `($l-3)/2` as `$l/2-1` - which is good enough for the `substr` to work.
-say @s while next_perm && $count--;
+```perl
+sub middle3compact {
+ my$l=length(my$n=abs$_[0]);
+ return$l<3?'Too short':$l%2?substr$n,$l/2-1,3:'Even digits';
+}
```
-# Task 2 - Distinct Terms Count
+# Task 2 - Validate SEDOL
-***You are given 2 positive numbers, `$m` and `$n`. Write a script to generate multiplcation table and display count of distinct terms.***
+***You are given 7-characters alphanumeric SEDOL. Write a script to validate the given SEDOL. Print 1 if it is a valid SEDOL otherwise 0.***
## Solution
-Number 2 again is the easier code this week...
-We just loop through the two indicies and make a note of each product as a keys of a hash. And return scalar
+You find about SEDOL numbers on Wikipedia at https://en.wikipedia.org/wiki/SEDOL.
+
+The consist of 6 digits/consonants + a checksum digit. The weighted sum of the 6 digits + the checksum is a multiple of 10.
+The weights are 1, 3, 1, 7, 3 and 9 for the six digits and the checksum.
+
+We have to:
+ * validate the number is a SEDOL number
+ * compute the weighted sum
+ * check to see if it is a multiple of 10
```perl
- my($m,$n,%x) = @_;
- for my $i (1..$m) {
- $x{$i*$_}++ for 1..$n;
- }
- return scalar keys %x;
+sub is_sedol {
+## Check correct format... numbers and consonants only
+ return 0 unless $_[0] =~ m{^[0-9B-HJ-NP-TW-Z]{6}\d$};
+
+## Accumulator and weights for each charachter
+ my( $t, @w ) = qw(0 1 3 1 7 3 9 1);
+
+## Calculate SEDOL sum... note YODA sum -55 + ord $_ to avoid precedence issue
+ $t += ( /\d/ ? $_ : -55 + ord $_ ) * shift @w for split //, $_[0];
+
+## Return true (1) if total modulo 10 is 0, and false (0) otherwise
+ return $t % 10 ? 0 : 1;
+}
```
+Again we can compact the code - by removing spaces and a couple of rewrites:
-If `$m` & `$n` are large (and similar) there may be gain in separating the rectangle into a square and a rectangle - and only compute products for one half of the triangle...
+ * replace `unless $x=~//` with `if $x!~//`;
+ * replace `$x?0:1` with `1^!$x`.
+
+```perl
+sub is_sedol_compact {
+ return 0 if$_[0]!~/^[0-9B-HJ-NP-TW-Z]{6}\d$/;
+ my($t,@w)=qw(0 1 3 1 7 3 9 1);
+ $t+=(/\d/?$_:-55+ord$_)*shift@w for split//,$_[0];
+ 1^!$t%10;
+}
+```