aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark <53903062+andemark@users.noreply.github.com>2024-03-16 11:56:29 +0000
committerMark <53903062+andemark@users.noreply.github.com>2024-03-16 11:56:29 +0000
commit473c714ee1f14bc4abbfd35b284392a567e36c02 (patch)
treed636048008a3b73f0d8f36e2f051f75f797cfa12
parent2bedb7bfa99f81df85ed29b48a10bfd9e10a9c5e (diff)
downloadperlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.tar.gz
perlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.tar.bz2
perlweeklychallenge-club-473c714ee1f14bc4abbfd35b284392a567e36c02.zip
blog for ch-2
-rw-r--r--challenge-260/mark-anderson/raku/blog-2.md143
-rw-r--r--challenge-260/mark-anderson/raku/ch-2.raku6
2 files changed, 146 insertions, 3 deletions
diff --git a/challenge-260/mark-anderson/raku/blog-2.md b/challenge-260/mark-anderson/raku/blog-2.md
new file mode 100644
index 0000000000..3ed5fccd92
--- /dev/null
+++ b/challenge-260/mark-anderson/raku/blog-2.md
@@ -0,0 +1,143 @@
+# Weekly Challenge #260
+
+### Task 2: Dictionary Rank
+**Submitted by: Mark Anderson**
+
+You are given a word, ```$word```.
+
+Write a script to compute the dictionary rank of the given word.
+
+#### Example 1
+```
+Input: $word = 'CAT'
+Output: 3
+
+All possible combinations of the letters:
+CAT, CTA, ATC, TCA, ACT, TAC
+
+Arrange them in alphabetical order:
+ACT, ATC, CAT, CTA, TAC, TCA
+
+CAT is the 3rd in the list.
+Therefore the dictionary rank of CAT is 3.
+```
+
+#### Example 2
+```
+Input: $word = 'GOOGLE'
+Output: 88
+```
+
+#### Example 3
+```
+Input: $word = 'SECRET'
+Output: 255
+```
+
+---
+
+### Solution
+
+One approach is to create all permutations, sort them, and find the index of ```$word```.
+
+This is fine for short words but there's a better solution for long words.
+
+There are numerous videos on youtube explaining the algorithm - I think this a good one [https://www.youtube.com/watch?v=-MpL0X3AHAs](https://www.youtube.com/watch?v=-MpL0X3AHAs)
+
+Here's the gist of the algorithm:
+
+1. Find the rank of each letter.
+
+ ```
+ G O O G L E
+ 1 3 3 1 2 0
+ ```
+
+2. For each letter, find the number of letters to its right that have a lower rank.
+
+ ```
+ G O O G L E
+ 1 3 3 1 1 0
+ ```
+
+3. For each letter, take the number of repeating letters from that letter to the end of the string.
+ Take the factorial of each result and multiply them together.
+
+ ```
+ G O O G L E
+ 2!*2! 2! 1! 1! 1! 1!
+ ```
+
+ Starting with the first letter, there are 2 Gs and 2 Os so we end up with 2!*2!.
+ The next letter is O. From that letter to the end of the string there is just the repeating O so we end up with 2!
+ and so on.
+
+4. Take the terms from step 2 and divide them by the terms from step 3.
+
+ ```
+ G O O G L E
+ 1/4 3/2 3/1 1/1 1/1 0/1
+ ```
+
+5. Create the sequence ```$word```.end...0 and take the factorial of each term.
+
+ ```
+ G O O G L E
+ 5! 4! 3! 2! 1! 0!
+ ```
+
+6. Multipy the terms from step 4 with the terms from step 5.
+
+ ```
+ G O O G L E
+ 120/4 (3*24)/2 3*6 1*2 1*1 0*1
+ ```
+
+7. Sum the terms from step 6 and add 1 for a result of 88.
+ ```
+ G O O G L E
+ 30 + 36 + 18 + 2 + 1 + 0 + 1 = 88
+ ```
+### My translation to Raku:
+
+```
+#!/usr/bin/env raku
+use experimental :cached;
+
+say rank('google');
+
+sub postfix:<!>($n) is cached { [*] 1..$n }
+
+sub rank($word)
+{
+ my @w = $word.comb;
+ my @ranks = @w.sort.squish.antipairs.Map{@w};
+ my $bag = @ranks.BagHash;
+
+ my @n = gather for @ranks -> $r
+ {
+ my @less-than = $bag.keys.grep(* < $r);
+ take ([+] $bag{@less-than}) / ([*] $bag.values>>!);
+ $bag{$r}--
+ }
+
+ 1 + [+] @n Z* (@ranks.end...0)>>!
+}
+```
+
+
+For step 3 I originally had this in the for loop:
+
+```
+my @repeated = $bag.values.grep(* > 1);
+take ([+] $bag{@less-than}) / ([*] @repeated>>!);
+```
+
+but grepping for values > 1 isn't necessary since 1! == 1 and then multiplying by that 1
+doesn't change anything.
+
+[The full program.](https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-260/mark-anderson/raku/ch-2.raku)
+
+Thank you for reading my solution to the [Weekly Challenge #260 Task #2.](https://theweeklychallenge.org/blog/perl-weekly-challenge-260/)
+
+*-Mark Anderson*
diff --git a/challenge-260/mark-anderson/raku/ch-2.raku b/challenge-260/mark-anderson/raku/ch-2.raku
index 5ce6cbbee5..f9bfe1af2b 100644
--- a/challenge-260/mark-anderson/raku/ch-2.raku
+++ b/challenge-260/mark-anderson/raku/ch-2.raku
@@ -14,10 +14,10 @@ is rank('1100010001100001111100000010101010001101111111111100101011100001').Int,
sub postfix:<!>($n) is cached { [*] 1..$n }
-sub rank($s)
+sub rank($word)
{
- my @a = $s.comb;
- my @ranks = @a.sort.squish.antipairs.Map{@a};
+ my @w = $word.comb;
+ my @ranks = @w.sort.squish.antipairs.Map{@w};
my $bag = @ranks.BagHash;
my @n = gather for @ranks -> $r