aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad S Anwar <Mohammad.Anwar@yahoo.com>2023-03-13 07:46:00 +0000
committerGitHub <noreply@github.com>2023-03-13 07:46:00 +0000
commit42c2d3ce36061d0b889fc60545fe6740198dd94d (patch)
tree4b0ab0a649f2bf06511acb9ebe45e42931977cad
parenta8b1837fcd58b7589791e42b2ef4788e0e8ed7d7 (diff)
parentd6678cdb0f720fef4dfcaa6e80396a3b546b2518 (diff)
downloadperlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.tar.gz
perlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.tar.bz2
perlweeklychallenge-club-42c2d3ce36061d0b889fc60545fe6740198dd94d.zip
Merge pull request #7712 from drbaggy/master
Finally had time to write up!
-rw-r--r--challenge-207/james-smith/README.md110
-rw-r--r--challenge-207/james-smith/blog.txt1
-rw-r--r--challenge-207/james-smith/perl/ch-1.pl22
-rw-r--r--challenge-207/james-smith/perl/ch-2.pl21
4 files changed, 110 insertions, 44 deletions
diff --git a/challenge-207/james-smith/README.md b/challenge-207/james-smith/README.md
index 4c0ad820a2..367b308981 100644
--- a/challenge-207/james-smith/README.md
+++ b/challenge-207/james-smith/README.md
@@ -1,7 +1,7 @@
-[< Previous 205](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-205/james-smith) |
-[Next 207 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-207/james-smith)
+[< Previous 206](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-206/james-smith) |
+[Next 208 >](https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-208/james-smith)
-# The Weekly Challenge 206
+# The Weekly Challenge 207
You can find more information about this weeks, and previous weeks challenges at:
@@ -13,69 +13,91 @@ 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-2065/james-smith
+https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-207/james-smith
-# Task 1: Shortest Time
+# Task 1: Keyboard Word
-***You are given a list of time points, at least 2, in the 24-hour clock format `HH:MM`. Write a script to find out the shortest time in minutes between any two time points.***
+***You are given an array of words. Write a script to print all the words in the given array that can be types using alphabet on only one row of the keyboard. (Assuming as English this is a QWERTY keyboard)***
## Solution
-We will do a pairwise comparison of each pair. The shortest time for any pair is either going from the absolute differences in times directly - OR going through midnight. These are `abs( t1 - t2 )` or `abs( t1 + t2 - 1440 )`. The code becomes:
+The obvious solution here is to use a regular expression, where each row of the keyboard is separated by a `|` to make them separate clauses.
```perl
-sub shortest_time {
- my $min = 1_440, @_ = map { @Q = split /:/; $Q[0]*60 + $Q[1] } @_;
- while( defined (my $t = shift) ) {
- abs( $t-$_ ) < $min && ( $min = abs $t-$_ ),
- abs( $t+$_-1_440 ) < $min && ( $min = abs $t+$_-1_440 ) for @_;
- }
- $min
-}
+sub keyboard_words { grep { m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } @_ }
```
-Now how efficient is this - though - is there a better way to use built-in perk functions?
-
-If we sort the times in order, we only have to compare the `n` gaps, from the last to the first through midnight and each of the subsequent neighbours.
-
-This gives us two alternative code blocks:
+We can loop through a file with the following code to find the longest keyboard words in the dictionary
```perl
-sub shortest_time {
- @_ = map { my @Q = split /:/; $Q[0]*60 + $Q[1] } sort @_;
- my $min = 1440 + (my $t = shift) - $_[-1];
- ($_-$t<$min) && ($min=$_-$t), $t=$_ for @_;
- $min
-}
+m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i && print while <>
```
-or:
+**or** as a bash one-liner:
-```perl
-sub shortest_time {
- @_ = sort { $a<=>$b } map { my @Q = split /:/; $Q[0]*60 + $Q[1] } @_;
- my $min = 1440 + (my $t = shift) - $_[-1];
- ($_-$t<$min) && ($min=$_-$t), $t=$_ for @_;
- $min
-}
+```bash
+perl -ne 'm{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i&&print' /usr/share/dict/british-english-huge
```
-Which of these is fastest? The `sort` method is much more efficient than the pairwise approach (It's `O(n.log n)` where the pairwise solution is `O(n^2)`. Of the two the second numeric `sort` after the `map` if slightly faster than the `map` after the string `sort`.
+This gives us the following for longest words:
+
+Length 11:
+
+ * rupturewort
+
+Length 10:
+ * peppertree
+ * pepperwort
+ * perpetuity
+ * perruquier
+ * pirouetter
+ * prerequire
+ * proprietor
+ * repertoire
+ * typewriter
+
+Note these are all on the top row of the keyboard - So no **typewriter** isn't the longest word in the English language you can make from the top row of the keyboard.
+
+Using this extreme dictionary - we have:
-# Task 2: Array Pairings
+| Length | Count |
++--------+-------+
+| 11 | 1 |
+| 10 | 9 |
+| 9 | 27 |
+| 8 | 70 |
+| 7 | 128 |
+| 6 | 224 |
+| 5 | 278 |
+| 4 | 322 |
+| 3 | 285 |
+| 2 | 218 |
+| 1 | 52 |
-***You are given an array of integers having even number of elements. Write a script to find the maximum sum of the minimum of each pairs.***
+Note: the definition of a word is a bit vague at times....
+
+Note: there are 5 9-letter words which are not from the top row - these are all of Jewish origin.
+
+# Task 2: H-index
+
+***You are given an array of integers containing citations a researcher has received for each paper. Write a script to compute the researcher’s H-Index. For more information please checkout the wikipedia page.***
+
+***The H-Index is the largest number h such that h articles have at least h citations each. For example, if an author has five publications, with 9, 7, 6, 2, and 1 citations (ordered from greatest to least), then the author’s h-index is 3, because the author has three publications with 3 or more citations. However, the author does not have four publications with 4 or more citations.***
## Solution
-There is a trick here - the optimal solution is achieved by sorting the array into order and then chunking into to pairs... Then take the minimum of each...
+This is actually relatively straight forward (we will assume that the reference counts are in order).
```perl
-sub max_sum_pair_min {
- my $t = 0, @_ = sort {$a<=>$b} @_;
- $t += shift, shift while @_;
- $t
-}
+sub h_index { ( $_[$_]>$_) && return $_+1 for reverse 0..$#_ }
+sub h_index_2 { pop @_ while $_[-1] < @_; 0 + @_ }
+sub h_index_3 { ( $_[$_]>$_) || return $_ for 0..$#_; 0+@_ }
```
-When we `shift`, `shift` the first value is added to the total, the second value is discarded.
+We can either start at the beginning of the list and count backwards *OR* from the start.
+
+`h_index_3` starts from the beginning of the list. We assume if we are not past the threshold then the `h-index` is the previous index - as in the real world our list is 1-based and in the perl world 0-based - then this is just `$_`. We short cut the loop and return the value. If we don't short cut the loop then the index must be the length of the list.
+
+`h_index` is slightly longer! But we start from the end of the list (we `reverse` the indicies). Again we use the same criteria but switch the *logic* to `&&` which is the equivalent of `if`. And loop until we match the criteria. In this case we return `$_+1` as it is the current one we are interested in. **Note** in this case we will always short cut the loop so need no additional `return` state - definitely a one-liner!
+
+`h_index_2` is effectively the same as 1, but removes the nasty use of `&&`/`||` to replace and `if`/`unless` - by putting the logic in the `while` statement and `pop`ping off values..
diff --git a/challenge-207/james-smith/blog.txt b/challenge-207/james-smith/blog.txt
new file mode 100644
index 0000000000..e6225e3f9b
--- /dev/null
+++ b/challenge-207/james-smith/blog.txt
@@ -0,0 +1 @@
+https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-207/james-smith/blog.txt
diff --git a/challenge-207/james-smith/perl/ch-1.pl b/challenge-207/james-smith/perl/ch-1.pl
new file mode 100644
index 0000000000..cc900a7700
--- /dev/null
+++ b/challenge-207/james-smith/perl/ch-1.pl
@@ -0,0 +1,22 @@
+#!/usr/local/bin/perl
+
+use strict;
+use warnings;
+use feature qw(say);
+use Test::More;
+
+my @TESTS = (
+ [ [qw(Hello Alaska Dad Peace)], 'Alaska Dad' ],
+ [ [qw(OMG Bye) ], '' ],
+);
+
+is( "@{[ keyboard_words( @{$_->[0]} ) ]}", $_->[1] ) for @TESTS;
+
+done_testing();
+
+sub keyboard_words { grep { m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } @_ }
+sub keyboard_word { $_[0] =~ m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i }
+
+## This one looks for all keyboard words in a file...
+keyboard_word($_)&&print while<>;
+m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i && print while <>;
diff --git a/challenge-207/james-smith/perl/ch-2.pl b/challenge-207/james-smith/perl/ch-2.pl
new file mode 100644
index 0000000000..bc06c9c57d
--- /dev/null
+++ b/challenge-207/james-smith/perl/ch-2.pl
@@ -0,0 +1,21 @@
+#!/usr/local/bin/perl
+
+use strict;
+use warnings;
+use feature qw(say);
+use Test::More;
+
+my @TESTS = (
+ [ [10,8,5,4,3], 4 ],
+ [ [25,8,5,3,3], 3 ],
+);
+
+is( h_index( @{$_->[0]} ), $_->[1] ) for @TESTS;
+is( h_index_2( @{$_->[0]} ), $_->[1] ) for @TESTS;
+is( h_index_3( @{$_->[0]} ), $_->[1] ) for @TESTS;
+
+done_testing();
+
+sub h_index { ( $_[$_]>$_) && return $_+1 for reverse 0..$#_ }
+sub h_index_2 { pop @_ while $_[-1] < @_; 0 + @_ }
+sub h_index_3 { ( $_[$_]>$_) || return $_ for 0..$#_; 0+@_ }