aboutsummaryrefslogtreecommitdiff
path: root/challenge-207/james-smith/README.md
blob: 367b30898162fbbe55f8a57c161a2d498807356d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
[< 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 207

You can find more information about this weeks, and previous weeks challenges at:

  https://theweeklychallenge.org/

If you are not already doing the challenge - it is a good place to practise your
**perl** or **raku**. If it is not **perl** or **raku** you develop in - you can
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-207/james-smith

# Task 1: Keyboard Word

***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

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 keyboard_words { grep { m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i } @_ }
```

We can loop through a file with the following code to find the longest keyboard words in the dictionary

```perl
m{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i && print while <>
```

**or** as a bash one-liner:

```bash
perl -ne 'm{^([qwertyuiop]+|[asdfghjkl]+|[zxcvbnm]+)$}i&&print' /usr/share/dict/british-english-huge
```

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:

| Length | Count |
+--------+-------+
|     11 |     1 |
|     10 |     9 |
|      9 |    27 |
|      8 |    70 |
|      7 |   128 |
|      6 |   224 |
|      5 |   278 |
|      4 |   322 |
|      3 |   285 |
|      2 |   218 |
|      1 |    52 |

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

This is actually relatively straight forward (we will assume that the reference counts are in order).

```perl
sub h_index   { ( $_[$_]>$_) && return $_+1 for reverse 0..$#_ }
sub h_index_2 { pop @_ while $_[-1] < @_; 0 + @_               }
sub h_index_3 { ( $_[$_]>$_) || return $_ for 0..$#_; 0+@_     }
```

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..