From 70a2c42a5eef1dab2b7ab75e3c7f6ffc8c8c1959 Mon Sep 17 00:00:00 2001
From: Patrick Spek <p.spek@tyil.nl>
Date: Fri, 5 Feb 2021 09:55:25 +0100
Subject: Move source files into src

---
 ...kerrank-solutions-python3-and-perl6-part-1.adoc | 465 +++++++++++++++++++++
 1 file changed, 465 insertions(+)
 create mode 100644 src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc

(limited to 'src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc')

diff --git a/src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc b/src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc
new file mode 100644
index 0000000..6dd01a6
--- /dev/null
+++ b/src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc
@@ -0,0 +1,465 @@
+---
+tags: Hackerrank Perl6 Python Python3 Programming Raku
+description: >
+  A number of solutions to Hackerrank challenges in both the Python 3 and the
+  Perl 6 programming languages. Compare the results and see which language
+  works best for you!
+---
+= Hackerrank solutions: Python 3 and Perl 6 (part 1)
+:toc: preamble
+
+I recently started at a new company, for which I will have to write Python 3
+code. To make sure I still know how to do basic stuff in Python, I started to
+work on some https://www.hackerrank.com/[Hackerrank challenges]. In this post,
+I will show solutions to some challenges to show the differences. I hope that I
+can show that Perl doesn't have to be the "write only" language that many
+people make it out to be.
+
+[NOTE]
+====
+I am _much_ more proficient in the Perl 6 programming language than in Python
+(2 or 3), so I might not always use the most optimal solutions in the Python
+variants. Suggestions are welcome via email, though I most likely won't update
+this post with better solutions. I ofcourse also welcome feedback on the Perl 6
+solutions!
+====
+
+== Challenges
+
+The challenges covered in this post are the
+https://www.hackerrank.com/domains/algorithms?filters%5Bsubdomains%5D%5B%5D=warmup[warmup
+challenges] you are recommended to solve when you make a new account. The code
+around the function I'm expected to solve won't be included, as this should be
+irrelevant (for now). Additionally, I may rename the sub to conform to
+https://en.wikipedia.org/wiki/Letter_case#Special_case_styles[kebab-case], as
+this is more readable (in my opinion), and allowed in Perl 6.
+
+=== Solve Me First
+
+This challenge is just a very simple example to introduce how the site works.
+It required me to make a simple `a + b` function.
+
+[source,py3]
+----
+def solveMeFirst(a,b):
+    return a+b
+----
+
+The Perl 6 variant isn't going to very different here.
+
+[source,perl6]
+----
+sub solve-me-first ($a, $b) {
+    $a + $b
+}
+----
+
+For those not familiar with Perl 6, the `$` in front of the variable names is
+called a https://docs.perl6.org/language/glossary#index-entry-Sigil[Sigil], and
+it signals that the variable contains only a single value.
+
+You may have noticed that there's also no `return` in the Perl 6 variant of
+this example. In Perl 6, the last statement in a block is also the implicit
+return value (just like in Perl 5 or Ruby).
+
+=== Simple Array Sum
+
+For this challenge I had to write a function that would return the sum of a
+list of values. Naturally, I wanted to use a `reduce` function, but Python 3
+does not support these. So I wrote it with a `for` loop instead.
+
+[source,py3]
+----
+def simpleArraySum(ar):
+    sum = 0
+
+    for i in ar:
+        sum += i
+
+    return sum
+----
+
+Perl 6 does have a `reduce` function, so I would use that to solve the problem
+here.
+
+[source,perl6]
+----
+sub simple-array-sum (@ar) {
+    @ar.reduce(sub ($a, $b) { $a + $b })
+}
+----
+
+Here you can see a different sigil for `@ar`. The `@` sigil denotes a list of
+scalars in Perl 6. In most other languages this would simply be an array.
+
+This code can be written even shorter, however. Perl 6 has
+https://docs.perl6.org/language/operators#index-entry-%5B%2B%5D_%28reduction_metaoperators%29[reduction
+meta-operators]. This allows you to put an operator between brackets, like
+`[+]`, to apply a certain operator as a reduce function.
+
+[source,perl6]
+----
+sub simple-array-sum (@ar) {
+    [+] @ar
+}
+----
+
+[NOTE]
+====
+After publishing this post I have learned that both Python 3 and Perl 6 have a
+`.sum` function that can also be called on the array, simplifying the code in
+both languages.
+====
+
+=== Compare the Triplets
+
+This challenge provides you with 2 lists of 3 elements each. The lists should
+be compared to one another, and a "score" should be kept. For each index, if
+the first list contains a larger number, the first list's score must be
+incremented. Similarly, if the second list contains a larger number on that
+index, the second list's score must be incremented. If the values are equal, do
+nothing.
+
+[source,py3]
+----
+def compareTriplets(a, b):
+    scores = [0, 0]
+
+    for i in range(3):
+        if a[i] > b[i]:
+            scores[0] += 1
+
+        if a[i] < b[i]:
+            scores[1] += 1
+
+    return scores
+----
+
+I learned that Python 3 has no `++` operator to increment a value by 1, so I
+had to use `+= 1` instead.
+
+[source,perl6]
+----
+sub compare-triplets (@a, @b) {
+    my @scores = [0, 0];
+
+    for ^3 {
+        @scores[0]++ if @a[$_] > @b[$_];
+        @scores[1]++ if @a[$_] < @b[$_];
+    }
+}
+----
+
+In Perl 6, the `^3` notation simply means a range from 0 to 3, non-inclusive,
+so `0`, `1`, `2`, meaning it will loop 3 times. The `$_` is called the
+__topic__, and in a `for` loop it is the current element of the iteration.
+
+Both of these loops could use a `continue` (or `next` in Perl 6) to skip the
+second `if` in case the first `if` was true, but for readability I chose not
+to.
+
+[NOTE]
+====
+After publishing this post I learned that Python 3 also supports the inline if
+syntax, just like Perl 6, so I could've used this in Python 3 as well.
+====
+
+=== A Very Big Sum
+
+In this challenge, you need to write the function body for `aVeryBigSum`, which
+gets an array of integers, and has to return the sum of this array. Both Python
+3 and Perl 6 handle the large integers transparently for you, so I was able to
+use the same code as I used for the simple array sum challenge.
+
+[source,py3]
+----
+def aVeryBigSum(ar):
+    sum = 0
+
+    for i in ar:
+        sum += i
+
+    return sum
+----
+
+And for Perl 6 using the `[+]` reduce meta-operation.
+
+[source,perl6]
+----
+sub a-very-big-sum (@ar) {
+    [+] @ar
+}
+----
+
+=== Plus Minus
+
+The next challenge gives a list of numbers, and wants you to return the
+fractions of its elements which are positive, negative or zero. The fractions
+should be rounded down to 6 decimals. I made a counter just like in the
+*Compare the Triplets* challenge, and calculated the fractions and rounded them
+at the end.
+
+[source,py3]
+----
+def plusMinus(arr):
+    counters = [0, 0, 0]
+
+    for i in arr:
+        if (i > 0):
+            counters[0] += 1
+            continue
+
+        if (i < 0):
+            counters[1] += 1
+            continue
+
+        counters[2] += 1
+
+    for i in counters:
+        print("%.6f" % (i / len(arr)))
+----
+
+For the Perl 6 solution, I went for a `given/when`, `map` and the `fmt`
+function to format the fractions.
+
+[source,perl6]
+----
+sub plus-minus (@arr) {
+    my @counters = [0, 0, 0];
+
+    for @arr -> $i {
+        given $i {
+            when * > 0 { @counters[0]++ }
+            when * < 0 { @counters[1]++ }
+            default    { @counters[2]++ }
+        }
+    }
+
+    @counters.map({ $_.fmt("%.6f").say });
+}
+----
+
+You may notice a number of statements do not have a terminating `;` at the end.
+In Perl 6, this is not needed if it's the last statement in a block (any code
+surrounded by a `{` and `}`.
+
+The `given/when` construct is similar to a `switch/case` found in other
+languages (but not Python, sadly), but uses the
+https://docs.perl6.org/language/operators#index-entry-smartmatch_operator[smartmatch
+operator] implicitly to check if the statements given to `when` are `True`. The
+`*` is the https://docs.perl6.org/type/Whatever[Whatever operator], which in
+this case will get the value of `$i`.
+
+Lastly, he `$_` in the `map` function is similar to inside a `for` loop,
+it's the current element. Since the code given to `map` is inside a block,
+there's no need for a `;` after `say` either.
+
+=== Staircase
+
+This challenge gives you an integer 𝓃, and you're tasked with "drawing" a
+staircase that is 𝓃 high, and 𝓃 wide at the base. The staircase must be made
+using `#` characters, and for the spacing you must use regular spaces.
+
+It seems that in Python, you _must_ specify the `i in` part oft the `for i in
+range`. Since I don't really care for the value, I assigned it to `_`.
+
+[source,py3]
+----
+def staircase(n):
+    for i in range(1, n + 1):
+        for _ in range(n - i):
+            print(" ", end="")
+
+        for _ in range(i):
+            print("#", end="")
+
+        print("")
+----
+
+In Perl 6, there's also a `print` function, which is like `say`, but does not
+append a `\n` at the end of the string. The `for` loop in Perl 6 allows for
+just a range to operate as expected. The `..` operator creates a range from the
+left-hand side up to the right hand side, inclusive.
+
+[source,perl6]
+----
+sub staircase ($n) {
+    for 1..$n -> $i {
+        print(" ") for 0..($n - $i);
+        print("#") for ^$i;
+        print("\n");
+    }
+}
+----
+
+=== Mini-Maxi Sum
+
+Here you will be given 5 integers, and have to calculate the minimum and
+maximum values that can be calculated using only 4 of them.
+
+I sort the array, and iterate over the first 4 values to calculate the sum and
+print it. I then do the same but sort it in reverse for the sum of the 4
+highest values.
+
+[source,py3]
+----
+def miniMaxSum(arr):
+    arr.sort()
+    sum = 0
+
+    for i in range(4):
+        sum += arr[i]
+
+    print(str(sum) + " ", end="")
+
+    arr.sort(reverse=True)
+    sum = 0
+
+    for i in range(4):
+        sum += arr[i]
+
+    print(str(sum))
+----
+
+Perl 6 has immutable lists, so calling `sort` on them will return a new list
+which has been sorted. I can call `reverse` on that list to get the highest
+number at the top instead. `head` allows me to get the first 4 elements in a
+functional way. You've already seen the meta-reduce operator `[+]`, which will
+get me the sum of the 4 elements I got from `head`. I wrap the calculation in
+parenthesis so I can call `print` on the result immediately.
+
+[source,perl6]
+----
+sub mini-maxi-sum (@arr) {
+    ([+] @arr.sort.head(4)).print;
+    print(" ");
+    ([+] @arr.sort.reverse.head(4)).print;
+}
+----
+
+=== Birthday Cake Candles
+
+In this challenge, you're given a list of numbers. You must find the highest
+number in the list, and return how often that number occurs in the list.
+
+It's fairly straightforward, I keep track of the current largest value as
+`size`, and a `count` that I reset whenever I find a larger value than I
+currently have.
+
+[source,py3]
+----
+def birthdayCakeCandles(ar):
+    size = 0
+    count = 0
+
+    for i in ar:
+        if i > size:
+            size = i
+            count = 0
+
+        if i == size:
+            count += 1
+
+    return count
+----
+
+The Perl 6 variant does not differ in how it solves the problem, apart from
+having a very different syntax of course.
+
+[source,perl6]
+----
+sub birthday-cake-candles (@ar) {
+    my ($size, $count) = (0, 0);
+
+    for @ar {
+        if ($_ > $size) {
+            $size = $_;
+            $count = 0;
+        }
+
+        $count++ if $size == $_;
+    }
+
+    $count;
+}
+----
+
+[NOTE]
+====
+On IRC, someone showed me a clean solution in Python 3: `return
+ar.count(max(ar))`. This feels like a much cleaner solution than what I had
+created.
+====
+
+=== Time Conversion
+
+This is the final challenge of this section on Hackerrank, and also this post.
+You're given a timestamp in 12-hour AM/PM format, and have to convert it to a
+24-hour format.
+
+I split the AM/PM identifier from the actual time by treating the string as a
+list of characters and taking two slices, one of the last two characters, and
+one of everything _but_ the last two characters. Then I split the time into
+parts, and convert the first part (hours) to integers for calculations. Next I
+set the hours to 0 if it's set to 12, and add 12 hours if the timestamp was
+post meridiem. Finally, I convert the hours back to a string with leading
+zeroes, and join all the parts together to form a timestamp again.
+
+[source,py3]
+----
+def timeConversion(s):
+    meridiem = s[-2:]
+    hours = int(s[:2])
+    rest = s[2:-2]
+
+    if (hours > 11):
+        hours = 0
+
+    if (meridiem.lower() == "pm"):
+        hours += 12
+
+    return ("%02d:%s" % (hours, rest))
+----
+
+The Perl 6 solution again doesn't differ much from the Python solution in terms
+of the logic it's using to get the result. The biggest difference is that in
+Perl 6, strings can't be accessed as lists, so I use the `substr` method to
+extract the parts that I want. The first one starts at `*-2`, which means 2
+places before the end. The others get a
+https://docs.perl6.org/type/Range[`Range`] as argument, and will get the
+characters that exist in that range.
+
+[source,perl6]
+----
+sub time-conversion ($s) {
+    my $meridiem = $s.substr(*-2);
+    my $hours = $s.substr(0..2).Int;
+    my $rest = $s.substr(2..*-2);
+
+    $hours = 0 if $hours > 11;
+    $hours += 12 if $meridiem.lc eq "pm";
+
+    sprintf("%02d:%s", $hours, $rest);
+}
+----
+
+The `.Int` method converts the `Str` object into an `Int` object, so we can
+perform calculations on it. The `eq` operator checks specifically for
+https://docs.perl6.org/routine/eq[__string equality__]. Since Perl 6 is a
+https://en.wikipedia.org/wiki/Gradual_typing[gradually typed programming
+language], there's a dedicated operator to ensure that you're checking string
+equality correctly.
+
+== Wrap-up
+
+These challenges were just the warm-up challenges I was given after creating a
+new account and choosing Python as a language to use. I intend to write up more
+posts like this, for the near future I'll stick to Python 3 challenges since I
+want to get better at that specific language for work.
+
+This is also the first post in which I have tried this format to show off two
+languages side-by-side, and to highlight differences in how you can accomplish
+certain (relatively simple) tasks with them. If you have suggestions to improve
+this format, do not hesitate to contact me. I am always open for feedback,
+preferably via email. You can find my contact details on the link:/[homepage].
+
-- 
cgit v1.1

