diff options
Diffstat (limited to 'src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc')
-rw-r--r-- | src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc | 465 |
1 files changed, 0 insertions, 465 deletions
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 deleted file mode 100644 index 6dd01a6..0000000 --- a/src/_posts/2018-09-13-hackerrank-solutions-python3-and-perl6-part-1.adoc +++ /dev/null @@ -1,465 +0,0 @@ ---- -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]. - |