From 9fc3c01987beb7bc11fb628f9b5ec3817c239ca3 Mon Sep 17 00:00:00 2001 From: Patrick Spek Date: Thu, 11 Oct 2018 08:04:50 +0200 Subject: Rectify the date on "Hackerrank solutions: Python 3 and Perl 6 (part 2)" --- ...kerrank-solutions-python3-and-perl6-part-2.html | 715 --------------------- ...kerrank-solutions-python3-and-perl6-part-2.html | 715 +++++++++++++++++++++ 2 files changed, 715 insertions(+), 715 deletions(-) delete mode 100644 _posts/2018-09-14-hackerrank-solutions-python3-and-perl6-part-2.html create mode 100644 _posts/2018-10-11-hackerrank-solutions-python3-and-perl6-part-2.html (limited to '_posts') diff --git a/_posts/2018-09-14-hackerrank-solutions-python3-and-perl6-part-2.html b/_posts/2018-09-14-hackerrank-solutions-python3-and-perl6-part-2.html deleted file mode 100644 index 5594bc2..0000000 --- a/_posts/2018-09-14-hackerrank-solutions-python3-and-perl6-part-2.html +++ /dev/null @@ -1,715 +0,0 @@ ---- -title: "Hackerrank solutions: Python 3 and Perl 6 (part 2)" -layout: language-war -tags: Hackerrank Perl6 Python3 Programming Comparison -description: > - A number of solutions to Hackerrank challenges in both the Python 3 and the - Perl 6 programming languages. This is the second part of the series, and will - work through the subdomain of Strings. ---- - -{% markdown %} -# Hackerrank solutions: Python 3 and Perl 6 (part 2) -{% endmarkdown %} - -{% markdown %} -As a continuation of the [previous -part](/post/2018/09/13/hackerrank-solutions-python3-and-perl6-part-1/) of this -series, I will be continuing to work through some Hackerrank challenges for -Python 3, and compare the solutions to how I would solve them in a language I'm -more proficient in, Perl 6. In this post, I will work through some of the -Python 3 string challenges from Hackerrank. - -Raiph [posted a comment on -Reddit](https://www.reddit.com/r/perl6/comments/9ffc2p/hackerrank_solutions_python_3_and_perl_6_part_1/e5xml3m) -suggesting a slightly different layout, which I will be using for this post. -Additional comments are always welcome as I try to improve the format. -{% endmarkdown %} - -{% admonition_md Disclaimer %} -Due to some comments I had on the previous article, I want to make some -additional constraints I adhere to personally clear. - -I don't want to make use of `import` (or `use` for Perl 6) statements if these -were not provided in the challenge template themselves. I do this because I -want to stick to the challenges as closely as possible. Another reason is -because it would invite all sorts of discussion that I could've used any module -for it, and then discuss which module would've solved it best. -{% endadmonition_md %} - -{% markdown %} -## Challenges -{% endmarkdown %} - -
-
- -{% markdown %} -### String Split and Join - -This challenge involves a string containing spaces, where the spaces are to be -replaced with dashes (`-`) instead. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##K6gsycjPM/7/PyU1TaG4ICezJD4xLyU@Kz8zTyMnMy9V04pLAQiKUktKi/IUlHSV9OBSemDlGkoKSpqa/wuKMvNKNNAMyMwrKC3R0ARKp@XnKyQlFgFxFQA %} -def split_and_join(line): - return "-".join(line.split(" ")) -{% endhighlight %} - -
-
- -{% markdown %} -I personally am not too fond that `join` takes a list of words to join -together, whereas `split` takes a word to split with. It feels a little -inconsistent. It also doesn't allow me to read the code logically from left to -right. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhuCAns0Q3MS9FNys/M09BQyUnMy9VU6GaSwEIwBw9sBINJQUlTT2QGg0lXSVNrtr/KlqefnrFOaVFBXpqqKboFSdW/k/Lz1dISiwC4ioA %} -sub split-and-join ($line) { - $line.split(" ").join("-") -} -{% endhighlight %} - -
-
- -{% markdown %} -The Perl 6 solution to the challenge does the same as the Python variant. Even -the function names are the same! The biggest difference is that I can chain the -functions from left to right, leading to clearer code. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### What's Your Name? - -The next challenge is a simply string formatting task. You get two inputs, a -first name and a last name, and have to put it in a string which will be -printed to `STDOUT`. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##XYzBCsIwEETv/YqxUEigePHmD@jZm6cSyRYj22ww2UK/PobqyWEOAzPz0laeEk@1epqR3iGWaVbmKbqFjBvxsOcOTXtl@isxC4bcfMBdFC/NBZ54JY@2EKQdeOwx4Pu39R8bYtJi7IhfsPWiwUu3uoib5KzLBw %} -def print_full_name(a, b): - print("Hello %s %s! You just delved into python." % (a, b)) -{% endhighlight %} - -
-
- -{% markdown %} -Before you begin, I know this can be done using `f""` strings, and that was my -first attempt to use as well. However, Hackerrank did not accept this, -complaining about invalid syntax, so I assume they're running an older Python 3 -than I do. - -That said, this is a simple `printf` formatted string, which then accepts a -tuple of parameters to put into the string. `printf` formatted string are very -powerful in their possibilities, and it's clear to read. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhoCgzr0Q3rTQnRzcvMTdVQyVRR0ElSVOhmksBCIoTKxWUPFJzcvIVVBKB4ooKkfmlClmlxSUKKak5ZakpCkDd@QoBQPMUzPSUuGr/Y5in5emnl55aAjQVytL875NYVFTJFZ6YkwMA %} -sub print-full-name($a, $b) { - say "Hello $a $b! You just delved into Perl 6." -} -{% endhighlight %} - -
-
- -{% markdown %} -Perl 6 has double-quote semantics that many people may be familiar with from -other languages. When you insert a variable in a double-quoted string, it's -`.Str` value will be used. That is to say, the value will be converted to a -`Str` if required, and then put into the string. - -If you need it or want it for clarity, you can also use `"Hello {$a}"` in Perl -6, allowing you to use it similarly to Python 3's `f""` strings. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### Mutations - -You are given a string _string_, an integer _position_ and a character -_character_. In _string_, replace the character at _position_ to the given -_character_. The position is counted from starting point 0, so I don't have to -think about differences between what a human or computer considers to be -position 1 in a string. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##VY5BC8IwDIXv/RVhpxaKIN4Ef4mIjNm5iCYlTQ/79bXrpmIuyeN975E468R0KOUWRnhl7TVckwrS3a7LQ@SEikwehqmXftAg7migzqITnOCJSTfc/YzzJ3ipyDdqGiBBsxB03e7BSLbxrsTaoPb/C6SY1ToPi7WJptbLlZHZ7I28AQ %} -def mutate_string(string, position, character): - chars = list(string) - chars[position] = character - - return "".join(chars) -{% endhighlight %} - -
-
- -{% markdown %} -This is basically what the example showed as well that came with the challenge, -so wasn't too hard to solve. My only complaint was that I couldn't call my list -"list", because that's a reserved keyword. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEkht7QksSRVt7ikKDMvXUFDBcLQUVApyC/OLMnMzwMykzMSixKTS1KLNBWquRSAILdSwSEns7hEwVYBqkEvOT83yRosCZaJhuuPBSmCm2DNhVCjl5WfmWfNVfsfxQ0aKlqefnrpqSVAizFYmnrFiZX/0/LzuQy5igA %} -sub mutate-string ($string, $position, $character) { - my @list = $string.comb; - @list[$position] = $character; - - @list.join; -} -{% endhighlight %} - -
-
- -{% markdown %} -The Perl 6 variant does the same things as the Python variant. `comb` without -parameters converts a string to a list of characters, and `join` without -parameters joins a list together to a string. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### Find a String - -In the following challenge you are given a string _string_, and a substring -_sub\_string_. The challenge is to find how often a substring occurs in the -_string_. The substrings may overlap one another, so the string `"ABCDCDC"` -contains the substring `"CDC"` twice. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##XU67CsMwDNz9FTfaxENKt4CHPv4ilNCHkwqKbBx76Ne7bhxIqYSQdNzp5N/x6Xif88OOuLvEcZjTbY6BeJK1aRRkqLPqBEosRBi0YllHF0AgRrjyZGWr8bK8qtUq@QaNqGBPHaGprO32Bcb8eG26zbIx2FXPYGMKXOHsCz/K//eJfYpSaayDUvlwPJ1LilIf %} -def count_substring(string, sub_string): - count = 0 - - for i in range(0, len(string)): - if string[i:i + len(sub_string)] == sub_string: - count += 1 - - return count -{% endhighlight %} - -
-
- -{% markdown %} -As solution to this challenge I loop through the entire _string_, and check -whether it contains the _sub\_string_ at that point. If it does, I increment -_count_ by 1. Now, I learned that Python also has the inline `if`, just like -Perl 6 does, however, it also *needs* an `else` block. That put me off from -using it in this situation. I think it puts me off from using it in most -situations, actually. With an `else` coming after it, it just becomes messy to -read, in my opinion. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEkhOb80r0QXyCouKcrMS1fQUIEwdBRUgIK6EI6mQjWXAhDkViqogDUo2CoYWHOBxdLyixTioJr0kjMSi4qhikEAolpbWyEzTQGmBmKXhko8ihUQrZoKqYXIotZgk2ohNkEMs@aq/Y/maA0VLU8/vfTUEqCJUJamXnFi5X9HJ2cXIOQCYgA %} -sub count-substring ($string, $sub-string) { - my $count = 0; - - for ^$string.chars { - $count++ if $string.substr($_, $sub-string.chars) eq $sub-string; - } - - $count; -} -{% endhighlight %} - -
-
- -{% markdown %} -The Perl 6 solution has no special gimmicks compared to the Python version, it -also loops through the _string_ and looks for a match on the _sub\_string_ on -each location. One of the differences you can see is that I use `.chars` as a -method on the strings. This returns the number of characters found in a string, -and is actually aware of Unicode graphemes, unlike Python's `len` function. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### String Validators - -In the following challenge, the program is given a string _s_, and have to -validate a number of properties on this string. These are, in order, whether -they contain - -- alphanumeric characters (a-z, A-Z or 0-9), -- alphabetic characters (a-z or A-Z), -- digits (0-9), -- lowercase characters (a-z), -- uppercase characters (A-Z). - -If any character in the given string passes a validation, it must print -`"True"`, otherwise it must print `"False"`. - -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##hZLNioMwEIDvPsXQPdTAIrS9CR72sk@wt1JCVtMaqklIIqWUPrubn6p1MZib38x8zmQi76YW/ND37AwYc9JSjKEoYItxSxjHeJsnYI@GAhiXnUlR4kFZ0/Lq6MN/urMhDe/aTQ7fpNH0853Lmizwil2YWeCNuFG1wDspJ@7xMzRzFso2RJRtERqmTapRPpbZybgwr4aPryZPQHjlazKmPUrfSqYBp/wCflRHk7jWzfhPa1FcG/JXtOGKZlqPYtohf0Ubbnim9SimHfJXtGFBM61HMe2QH7QQvFd6d@/K7zEkZg6lCI3hTAs1vkS3fAvd7l1s@pNUjA@Kow2dUN9//ZbVbn/4@AM %} -if __name__ == '__main__': - s = input() - - checks = { - "alnum": False, - "alpha": False, - "digit": False, - "lower": False, - "upper": False - } - - for char in list(s): - if not checks["alnum"] and char.isalnum(): - checks["alnum"] = True - - if not checks["alpha"] and char.isalpha(): - checks["alpha"] = True - - if not checks["digit"] and char.isdigit(): - checks["digit"] = True - - if not checks["lower"] and char.islower(): - checks["lower"] = True - - if not checks["upper"] and char.isupper(): - checks["upper"] = True - - keys = list(checks.keys()) - keys.sort() - - for key in keys: - print(checks[key]) -{% endhighlight %} - -
-
- -{% markdown %} -As stated in the disclaimer, I don't want to make use of any `import` -statements unless these are explicitly given in the original challenges. This -means I can't use regexes, as these are stuffed away in the `re` packages in -Python. Luckily, Python has the correct check available as a method on the -string object, so I can still check them in a single line. - -I first tried to call the methods on _s_ directly, but this seemed to require -the entire string to match the check, instead of just any character in the -string. So I had to loop through the string by character, which I did. If any -character is found to validate, the appropriate key in the _checks_ dict will -be set to `True`. Once I've walked through the entire string, I sort the _keys_ -from _checks_ so I can be sure they're printed in the right order. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 -tio=https://tio.run/##K0gtyjH7/7@4NEnB19HTT6GaSwEIcisVVIoVbBVUtDz99NJTS6y5wMLFiZUKxfkgqbo6BX2bxJy80lw7fWvscgUZiTjkUjLTM0twyOXkl6cW4ZArLSiAyNX@/@@YlJxiaGSsDAA %} -sub MAIN { - my $s = $*IN.get; - - say so $s ~~ //; - say so $s ~~ //; - say so $s ~~ //; - say so $s ~~ //; - say so $s ~~ //; -} -{% endhighlight %} - -
-
- -{% markdown %} -Perl 6 does have regexes available in the main namespace by default, so that -made this challenge a lot easier to work with. `$*IN` in a special variable -that refers to `STDIN`, and the `.slurp` method reads all remaining data from -the buffer. - -The next 5 lines all do a `say`, which acts like `print` in Python 3. The `so` -function coerces a value to become a `Bool`. When a `Bool` is given to `say`, -it will be coerced to a string representation again, and become either `"True"` -or `"False"`. The smartmatch operator `~~` has already been covered in the -previous post, so I recommend you read that as well if you haven't yet. - -In Perl 6, regexes are (usually) delimited by the `/` character. The ``, -`` etcetera parts are [predefined character classes][classes] in Perl 6 -regexes. These check for exactly what we need in the challenges, so were a good -pick to solve them. - -[classes]: https://docs.perl6.org/language/regexes.html#Predefined_character_classes -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### Text Wrap - -You are given a string _s_ and a width _w_. The string should be split over -multiple lines so it is never more wide than _w_. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##K6gsycjPM/7/PzO3IL@oRKEktaKkvCixgIsrJTVNAcTSKC4pysxL11HITayIL89MKcnQtOJSAIKi1JLSojwFpZg8Jb2s/Mw8DZhePRzaNP8XAIVKNMDSmXkFpSUamjoKIBEoBwj@Ozo5u7i6uXt4enn7@Pr5BwQGBYeEhoVHREZxmQIA %} -import textwrap - -def wrap(string, max_width): - return "\n".join(textwrap.wrap(string, max_width)) -{% endhighlight %} - -
-
- -{% markdown %} -This challenge introduces the first Python module: `textwrap`. This makes the -challenge very easy to solve as well, using the `wrap` function exposed by the -module. This function makes a list of strings, each no longer than the given -width. I then join these together with newlines to get the desired output. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhvCixQEFDpbikKDMvXUdBpTwzpSRDU6GaSwEIoMJ6yfm5SRpQKb2s/Mw8DaWYPCVNrtr/IO0aKlqefnrpqSVA7VCWnmdeiaZecWLlf0cnZxdXN3cPTy9vH18//4DAoOCQ0LDwiMgoLlMA %} -sub wrap ($string, $width) { - $string.comb($width).join("\n") -} -{% endhighlight %} - -
-
- -{% markdown %} -For the Perl 6 solution, I have not used an additional module, as all the -functionality are in the core namespace. I actually made a module in Perl 6 for -a less primitive wrapping functionality, called [`String::Fold`][string::fold]. - -In this solution, I use `comb` with the `$width` argument. This returns a list -of strings, each no longer than the given width, just like Python's -`textwrap.wrap`. I can then join these together with newlines as well to get -the same result. - -[string::fold]: https://modules.perl6.org/dist/String::Fold:cpan:TYIL -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### Designer Door Mat - -This challenge is more complex than previous challenges. The task at hand is to -"draw" a certain "design" as the output. For the input, you are given both a -height _y_ and a width _x_, however _x_ must always be _y_ × 3, so you can -ignore the second argument. - -This one is much simpler to explain using two examples. The first example is -the output if the input were `7 21`. -{% endmarkdown %} - -{% highlight text %} ----------.|.--------- -------.|..|..|.------ ----.|..|..|..|..|.--- --------WELCOME------- ----.|..|..|..|..|.--- -------.|..|..|.------ ----------.|.--------- -{% endhighlight %} - -{% markdown %} -In the second example, the input is `11 33`. -{% endmarkdown %} - -{% highlight text %} ----------------.|.--------------- -------------.|..|..|.------------ ----------.|..|..|..|..|.--------- -------.|..|..|..|..|..|..|.------ ----.|..|..|..|..|..|..|..|..|.--- --------------WELCOME------------- ----.|..|..|..|..|..|..|..|..|.--- -------.|..|..|..|..|..|..|.------ ----------.|..|..|..|..|.--------- -------------.|..|..|.------------ ----------------.|.--------------- -{% endhighlight %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##zZDNS8MwGMbv@SseMwbJlrbrehCEnWS3DS@CBxGpNFsCJQ1p5xD832s@Nh2I7GpyCHmf3/u8H/ZjUJ2pxnFyg@LQu@JNm0Kad9gkEKKk3qsBK2gzMKaNPQyM571ttX/58@KFk6NuBuWJEzpDRVTd7s45p3CGkqPAkhMywWNnERiy6xxabaRH4Wqzl6wUUcHc83cE/pjOvDZ1r2TvLRmL@MwbRctIfKuxYOonA7tI9E3xc/mQYV1A6bQPl2IKRjPqqYQL0PwzD/8fCx@7IHgcY6ubppVxAPLbMRZKSSxoqa8idV5xkfSn9eb@Ybum4gpOUslNd5Tur92FsMBCIPvfuxvHWyzLLw %} -#! /usr/bin/env python3 - -height = int((input().split())[0]) -width = height * 3 -half = int((height - 1) / 2) - -# Top half -for line in range(1, half + 1): - non_dashes = ((line * 2) - 1) - dashes = int((width - (non_dashes * 3)) / 2) - - print("%s%s%s" % ("-" * dashes, ".|." * non_dashes, "-" * dashes)) - -# Middle line -print("%s%s%s" % ( - "-" * (int(width / 2) - 3), - "WELCOME", - "-" * (int(width / 2) - 3) -)) - -# Lower half -for line in range(half, 0, -1): - non_dashes = ((line * 2) - 1) - dashes = int((width - (non_dashes * 3)) / 2) - - print("%s%s%s" % ("-" * dashes, ".|." * non_dashes, "-" * dashes)) -{% endhighlight %} - -
-
- -{% markdown %} -I split the code up in a top half, middle line and lower half, to make it -easier to reason about. The `for` loops contain some logic to get the right -output on every line. I found out that `range` supports a third argument, -allowing me to count down with it as well, which was perfect for this -situation. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##zZBBTsMwEEX3PsXgdpEgxVFSqSwiVqiLSi1skFiiIE@xpeBEdtpQhZyDo3CAHix0UpKGSuzxypp5/8/XL9Bm87adXEG4dTZ80SZEs4OCxoy97WGqUL@qEm5her28Fy7b2kJUuZVOKEylWJoy6bhKy1IR9iM4fMLstFFptgkGG68HAoh8OHxBnDA2gce8AALZJrcQCfFLVTM4PvIyuQlk6hS6zuqZzsQ@eSUDM9qfQgXH30hIyfzhNKlcugde84DDey9vai4@RDc4S5sLhiesofBrLWWGkGmDbOzl9QnoFqWc@c3TYnX3sF7U8DfCu0ZWeYX23Il3UYovLO7QOvzX7bTtDcTRNw %} -#! /usr/bin/env perl6 - -my $height = $*IN.slurp.words.head.Int; -my $width = $height × 3; -my $half-height = ($height - 1) ÷ 2; - -# Top half -for 1..$half-height { - my $non-dashes = ($_ × 2) - 1; - my $dashes = ($width - ($non-dashes × 3)) ÷ 2; - - say "{"-" x $dashes}{".|." x $non-dashes}{"-" x $dashes}"; -} - -# Middle line -say "{"-" x (($width ÷ 2) - 3)}WELCOME{ "-" x (($width ÷ 2) - 3)}"; - -# Lower half -for (1..$half-height).reverse { - my $non-dashes = ($_ × 2) - 1; - my $dashes = ($width - ($non-dashes × 3)) ÷ 2; - - say "{"-" x $dashes}{".|." x $non-dashes}{"-" x $dashes}"; -} -{% endhighlight %} - -
-
- -{% markdown %} -As usual, the code is functionally the same. I must admit I like the functional -style to get an `Int` from the first argument much more than the way I do it in -Python, though. - -A thing I learned is that the `..` operator that generates a sequence does not -have a way to make a sequence that counts down, so I had to use `.reverse` on a -sequence that counts up. I had expected this to Just Work as I expected and -count down if the left hand side would be larger than the right hand side. - -You may notice some fancy Unicode characters in the source, namely `×` for -multiplication, and ÷ for division. Perl 6 allows Unicode characters in the -source files, which can oftentimes lead to prettier code. In this particular -instance, there's no big difference in code readability, though. And for those -who don't yet have a modern editor that can make Unicode characters, do not -worry, as the ASCII equivalents (`*` and `/` respectively) still work as well. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -### String Formatting - -In this challenge, you are to produce a table with four columns. The columns -should contain the decimal, octal, hexadecimal and binary values of the row -numbers. The function receives an int _number_. The table should contain that -many rows, starting with row number 1. -{% endmarkdown %} - -
-
-
-
- -{% highlight python3 tio=https://tio.run/##jZFNCoMwEIX3nmIQhIQG0XYn9CwSTawpJoYYqVJ6dht/W7uQDlll3vveTKJ7W9bqMgyMF6CNUDYtaiOptZwh1cqMG5x44ErSLn0IZku4QsUV8p9Rkr38cJavWuxNYncJAoQCQ9WNo5jA3IcTxAtvLMZzIWnliI72YQkcmnvbWLRl4s1S53Y1JPV/lpJ3dJeUdDtjqzU36ACQCUVNv3iz49DNND0m8oMG1uNDAGgZhMyLkO/hyBKE8fD7EyNKKN1ahF33HL0B %} -def print_formatted(number): - max_width = len("{0:b}".format(number)) - - for i in range(1, number + 1): - decimal = "{0}".format(i).rjust(max_width) - octal = "{0:o}".format(i).rjust(max_width) - hexadecimal = "{0:x}".format(i).upper().rjust(max_width) - binary = "{0:b}".format(i).rjust(max_width) - - print("%s %s %s %s" % (decimal, octal, hexadecimal, binary)) -{% endhighlight %} - -
-
- -{% markdown %} -In the Python 3 solution I first calculate the max width I need to take into -account. Then I loop from 1 until _number_ to get the right amount of rows. -Each iteration, I format the number correctly, and then print it out using a -printf format string. - -The hardest part of this challenge was to get formatting right the way -Hackerrank wanted it. But I guess that was the entire point of the challenge. -{% endmarkdown %} - -
-
-
-
- -{% highlight perl6 tio=https://tio.run/##XY9NCsIwEIX3PcUQIiRiB1tEBPEA3bhxK0iq0VZMWpIUK1KvXmNb/HurGWbeN29KaS7ztrVVCqXJtQuPhVHCOXkARnWlUmk43APwUjegStThNT@4DFYwjDEVVrKY48YZ3GfC2OV7vYeF1nn0yVsYGd0/jMYSqGuYcTwXuWYECIcHkK0my6BDeDtEiMOhIcZLv2Dskh8Z3U2A7vo8C/6po/lXE3Pe52uCpv17mdFxssaTdJhox9t4@gQ %} -sub print-formatted ($number) { - my $max-width = $number.base(2).Str.chars; - my $format-string = ("%{$max-width}s" xx 4).join(" ") ~ "\n"; - - for 1..$number { - $format-string.printf($_, $_.base(8), $_.base(16), $_.base(2)); - } -} -{% endhighlight %} - -
-
- -{% markdown %} -The Perl 6 solution starts of the same, in that it first calculates the max -width I need to take into account. Next, however, I generate the format string -using the `$max-width` to make the `printf` subroutine pad it for me. The `xx` -operator makes a total of 4 such strings, and puts them into a list, which I -can then `join` together with a space character, and add a `\n` at the end of -it (the `~` operator is for string concatenation). - -I'm assuming something similar is possible in Python 3 as well, and I would -like to have an example so I can compare it more fairly. - -In the Perl 6 solution I am also able to make use of the `base` method to -convert the numbers into the right base, something I could not find for Python -3. -{% endmarkdown %} - -
-
-
-
- -{% markdown %} -## Wrap-up - -This time I did not do all of the challenges, as the post would probably get -too long. I still did 8 of them, and might do the rest of the string challenges -in a later part anyway. - -I still find Perl 6 to produce much cleaner code, which is shown best with the -first challenge. In Perl 6 (`$line.split(" ").join("-")`), I can read from left -to right to see what I'm doing: I have a `$line`, which I split, and then join. -In the Python variant (`"-".join(line.split(" "))`), it is much less clear what -the actual item I'm working on is, as it's hidden inbetween the `join` and -`split` calls. - -Of course, I'm still not an expert on Python 3 code, so I'm sure that there are -many parts that could be written in a cleaner fashion. I'm still open for -feedback to improve my Python 3 skills (hence I'm publishing these posts), so -please let me know if you know better ways to solve some challenges. -{% endmarkdown %} diff --git a/_posts/2018-10-11-hackerrank-solutions-python3-and-perl6-part-2.html b/_posts/2018-10-11-hackerrank-solutions-python3-and-perl6-part-2.html new file mode 100644 index 0000000..5594bc2 --- /dev/null +++ b/_posts/2018-10-11-hackerrank-solutions-python3-and-perl6-part-2.html @@ -0,0 +1,715 @@ +--- +title: "Hackerrank solutions: Python 3 and Perl 6 (part 2)" +layout: language-war +tags: Hackerrank Perl6 Python3 Programming Comparison +description: > + A number of solutions to Hackerrank challenges in both the Python 3 and the + Perl 6 programming languages. This is the second part of the series, and will + work through the subdomain of Strings. +--- + +{% markdown %} +# Hackerrank solutions: Python 3 and Perl 6 (part 2) +{% endmarkdown %} + +{% markdown %} +As a continuation of the [previous +part](/post/2018/09/13/hackerrank-solutions-python3-and-perl6-part-1/) of this +series, I will be continuing to work through some Hackerrank challenges for +Python 3, and compare the solutions to how I would solve them in a language I'm +more proficient in, Perl 6. In this post, I will work through some of the +Python 3 string challenges from Hackerrank. + +Raiph [posted a comment on +Reddit](https://www.reddit.com/r/perl6/comments/9ffc2p/hackerrank_solutions_python_3_and_perl_6_part_1/e5xml3m) +suggesting a slightly different layout, which I will be using for this post. +Additional comments are always welcome as I try to improve the format. +{% endmarkdown %} + +{% admonition_md Disclaimer %} +Due to some comments I had on the previous article, I want to make some +additional constraints I adhere to personally clear. + +I don't want to make use of `import` (or `use` for Perl 6) statements if these +were not provided in the challenge template themselves. I do this because I +want to stick to the challenges as closely as possible. Another reason is +because it would invite all sorts of discussion that I could've used any module +for it, and then discuss which module would've solved it best. +{% endadmonition_md %} + +{% markdown %} +## Challenges +{% endmarkdown %} + +
+
+ +{% markdown %} +### String Split and Join + +This challenge involves a string containing spaces, where the spaces are to be +replaced with dashes (`-`) instead. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##K6gsycjPM/7/PyU1TaG4ICezJD4xLyU@Kz8zTyMnMy9V04pLAQiKUktKi/IUlHSV9OBSemDlGkoKSpqa/wuKMvNKNNAMyMwrKC3R0ARKp@XnKyQlFgFxFQA %} +def split_and_join(line): + return "-".join(line.split(" ")) +{% endhighlight %} + +
+
+ +{% markdown %} +I personally am not too fond that `join` takes a list of words to join +together, whereas `split` takes a word to split with. It feels a little +inconsistent. It also doesn't allow me to read the code logically from left to +right. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhuCAns0Q3MS9FNys/M09BQyUnMy9VU6GaSwEIwBw9sBINJQUlTT2QGg0lXSVNrtr/KlqefnrFOaVFBXpqqKboFSdW/k/Lz1dISiwC4ioA %} +sub split-and-join ($line) { + $line.split(" ").join("-") +} +{% endhighlight %} + +
+
+ +{% markdown %} +The Perl 6 solution to the challenge does the same as the Python variant. Even +the function names are the same! The biggest difference is that I can chain the +functions from left to right, leading to clearer code. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### What's Your Name? + +The next challenge is a simply string formatting task. You get two inputs, a +first name and a last name, and have to put it in a string which will be +printed to `STDOUT`. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##XYzBCsIwEETv/YqxUEigePHmD@jZm6cSyRYj22ww2UK/PobqyWEOAzPz0laeEk@1epqR3iGWaVbmKbqFjBvxsOcOTXtl@isxC4bcfMBdFC/NBZ54JY@2EKQdeOwx4Pu39R8bYtJi7IhfsPWiwUu3uoib5KzLBw %} +def print_full_name(a, b): + print("Hello %s %s! You just delved into python." % (a, b)) +{% endhighlight %} + +
+
+ +{% markdown %} +Before you begin, I know this can be done using `f""` strings, and that was my +first attempt to use as well. However, Hackerrank did not accept this, +complaining about invalid syntax, so I assume they're running an older Python 3 +than I do. + +That said, this is a simple `printf` formatted string, which then accepts a +tuple of parameters to put into the string. `printf` formatted string are very +powerful in their possibilities, and it's clear to read. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhoCgzr0Q3rTQnRzcvMTdVQyVRR0ElSVOhmksBCIoTKxWUPFJzcvIVVBKB4ooKkfmlClmlxSUKKak5ZakpCkDd@QoBQPMUzPSUuGr/Y5in5emnl55aAjQVytL875NYVFTJFZ6YkwMA %} +sub print-full-name($a, $b) { + say "Hello $a $b! You just delved into Perl 6." +} +{% endhighlight %} + +
+
+ +{% markdown %} +Perl 6 has double-quote semantics that many people may be familiar with from +other languages. When you insert a variable in a double-quoted string, it's +`.Str` value will be used. That is to say, the value will be converted to a +`Str` if required, and then put into the string. + +If you need it or want it for clarity, you can also use `"Hello {$a}"` in Perl +6, allowing you to use it similarly to Python 3's `f""` strings. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### Mutations + +You are given a string _string_, an integer _position_ and a character +_character_. In _string_, replace the character at _position_ to the given +_character_. The position is counted from starting point 0, so I don't have to +think about differences between what a human or computer considers to be +position 1 in a string. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##VY5BC8IwDIXv/RVhpxaKIN4Ef4mIjNm5iCYlTQ/79bXrpmIuyeN975E468R0KOUWRnhl7TVckwrS3a7LQ@SEikwehqmXftAg7migzqITnOCJSTfc/YzzJ3ipyDdqGiBBsxB03e7BSLbxrsTaoPb/C6SY1ToPi7WJptbLlZHZ7I28AQ %} +def mutate_string(string, position, character): + chars = list(string) + chars[position] = character + + return "".join(chars) +{% endhighlight %} + +
+
+ +{% markdown %} +This is basically what the example showed as well that came with the challenge, +so wasn't too hard to solve. My only complaint was that I couldn't call my list +"list", because that's a reserved keyword. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEkht7QksSRVt7ikKDMvXUFDBcLQUVApyC/OLMnMzwMykzMSixKTS1KLNBWquRSAILdSwSEns7hEwVYBqkEvOT83yRosCZaJhuuPBSmCm2DNhVCjl5WfmWfNVfsfxQ0aKlqefnrpqSVAizFYmnrFiZX/0/LzuQy5igA %} +sub mutate-string ($string, $position, $character) { + my @list = $string.comb; + @list[$position] = $character; + + @list.join; +} +{% endhighlight %} + +
+
+ +{% markdown %} +The Perl 6 variant does the same things as the Python variant. `comb` without +parameters converts a string to a list of characters, and `join` without +parameters joins a list together to a string. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### Find a String + +In the following challenge you are given a string _string_, and a substring +_sub\_string_. The challenge is to find how often a substring occurs in the +_string_. The substrings may overlap one another, so the string `"ABCDCDC"` +contains the substring `"CDC"` twice. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##XU67CsMwDNz9FTfaxENKt4CHPv4ilNCHkwqKbBx76Ne7bhxIqYSQdNzp5N/x6Xif88OOuLvEcZjTbY6BeJK1aRRkqLPqBEosRBi0YllHF0AgRrjyZGWr8bK8qtUq@QaNqGBPHaGprO32Bcb8eG26zbIx2FXPYGMKXOHsCz/K//eJfYpSaayDUvlwPJ1LilIf %} +def count_substring(string, sub_string): + count = 0 + + for i in range(0, len(string)): + if string[i:i + len(sub_string)] == sub_string: + count += 1 + + return count +{% endhighlight %} + +
+
+ +{% markdown %} +As solution to this challenge I loop through the entire _string_, and check +whether it contains the _sub\_string_ at that point. If it does, I increment +_count_ by 1. Now, I learned that Python also has the inline `if`, just like +Perl 6 does, however, it also *needs* an `else` block. That put me off from +using it in this situation. I think it puts me off from using it in most +situations, actually. With an `else` coming after it, it just becomes messy to +read, in my opinion. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEkhOb80r0QXyCouKcrMS1fQUIEwdBRUgIK6EI6mQjWXAhDkViqogDUo2CoYWHOBxdLyixTioJr0kjMSi4qhikEAolpbWyEzTQGmBmKXhko8ihUQrZoKqYXIotZgk2ohNkEMs@aq/Y/maA0VLU8/vfTUEqCJUJamXnFi5X9HJ2cXIOQCYgA %} +sub count-substring ($string, $sub-string) { + my $count = 0; + + for ^$string.chars { + $count++ if $string.substr($_, $sub-string.chars) eq $sub-string; + } + + $count; +} +{% endhighlight %} + +
+
+ +{% markdown %} +The Perl 6 solution has no special gimmicks compared to the Python version, it +also loops through the _string_ and looks for a match on the _sub\_string_ on +each location. One of the differences you can see is that I use `.chars` as a +method on the strings. This returns the number of characters found in a string, +and is actually aware of Unicode graphemes, unlike Python's `len` function. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### String Validators + +In the following challenge, the program is given a string _s_, and have to +validate a number of properties on this string. These are, in order, whether +they contain + +- alphanumeric characters (a-z, A-Z or 0-9), +- alphabetic characters (a-z or A-Z), +- digits (0-9), +- lowercase characters (a-z), +- uppercase characters (A-Z). + +If any character in the given string passes a validation, it must print +`"True"`, otherwise it must print `"False"`. + +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##hZLNioMwEIDvPsXQPdTAIrS9CR72sk@wt1JCVtMaqklIIqWUPrubn6p1MZib38x8zmQi76YW/ND37AwYc9JSjKEoYItxSxjHeJsnYI@GAhiXnUlR4kFZ0/Lq6MN/urMhDe/aTQ7fpNH0853Lmizwil2YWeCNuFG1wDspJ@7xMzRzFso2RJRtERqmTapRPpbZybgwr4aPryZPQHjlazKmPUrfSqYBp/wCflRHk7jWzfhPa1FcG/JXtOGKZlqPYtohf0Ubbnim9SimHfJXtGFBM61HMe2QH7QQvFd6d@/K7zEkZg6lCI3hTAs1vkS3fAvd7l1s@pNUjA@Kow2dUN9//ZbVbn/4@AM %} +if __name__ == '__main__': + s = input() + + checks = { + "alnum": False, + "alpha": False, + "digit": False, + "lower": False, + "upper": False + } + + for char in list(s): + if not checks["alnum"] and char.isalnum(): + checks["alnum"] = True + + if not checks["alpha"] and char.isalpha(): + checks["alpha"] = True + + if not checks["digit"] and char.isdigit(): + checks["digit"] = True + + if not checks["lower"] and char.islower(): + checks["lower"] = True + + if not checks["upper"] and char.isupper(): + checks["upper"] = True + + keys = list(checks.keys()) + keys.sort() + + for key in keys: + print(checks[key]) +{% endhighlight %} + +
+
+ +{% markdown %} +As stated in the disclaimer, I don't want to make use of any `import` +statements unless these are explicitly given in the original challenges. This +means I can't use regexes, as these are stuffed away in the `re` packages in +Python. Luckily, Python has the correct check available as a method on the +string object, so I can still check them in a single line. + +I first tried to call the methods on _s_ directly, but this seemed to require +the entire string to match the check, instead of just any character in the +string. So I had to loop through the string by character, which I did. If any +character is found to validate, the appropriate key in the _checks_ dict will +be set to `True`. Once I've walked through the entire string, I sort the _keys_ +from _checks_ so I can be sure they're printed in the right order. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 +tio=https://tio.run/##K0gtyjH7/7@4NEnB19HTT6GaSwEIcisVVIoVbBVUtDz99NJTS6y5wMLFiZUKxfkgqbo6BX2bxJy80lw7fWvscgUZiTjkUjLTM0twyOXkl6cW4ZArLSiAyNX@/@@YlJxiaGSsDAA %} +sub MAIN { + my $s = $*IN.get; + + say so $s ~~ //; + say so $s ~~ //; + say so $s ~~ //; + say so $s ~~ //; + say so $s ~~ //; +} +{% endhighlight %} + +
+
+ +{% markdown %} +Perl 6 does have regexes available in the main namespace by default, so that +made this challenge a lot easier to work with. `$*IN` in a special variable +that refers to `STDIN`, and the `.slurp` method reads all remaining data from +the buffer. + +The next 5 lines all do a `say`, which acts like `print` in Python 3. The `so` +function coerces a value to become a `Bool`. When a `Bool` is given to `say`, +it will be coerced to a string representation again, and become either `"True"` +or `"False"`. The smartmatch operator `~~` has already been covered in the +previous post, so I recommend you read that as well if you haven't yet. + +In Perl 6, regexes are (usually) delimited by the `/` character. The ``, +`` etcetera parts are [predefined character classes][classes] in Perl 6 +regexes. These check for exactly what we need in the challenges, so were a good +pick to solve them. + +[classes]: https://docs.perl6.org/language/regexes.html#Predefined_character_classes +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### Text Wrap + +You are given a string _s_ and a width _w_. The string should be split over +multiple lines so it is never more wide than _w_. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##K6gsycjPM/7/PzO3IL@oRKEktaKkvCixgIsrJTVNAcTSKC4pysxL11HITayIL89MKcnQtOJSAIKi1JLSojwFpZg8Jb2s/Mw8DZhePRzaNP8XAIVKNMDSmXkFpSUamjoKIBEoBwj@Ozo5u7i6uXt4enn7@Pr5BwQGBYeEhoVHREZxmQIA %} +import textwrap + +def wrap(string, max_width): + return "\n".join(textwrap.wrap(string, max_width)) +{% endhighlight %} + +
+
+ +{% markdown %} +This challenge introduces the first Python module: `textwrap`. This makes the +challenge very easy to solve as well, using the `wrap` function exposed by the +module. This function makes a list of strings, each no longer than the given +width. I then join these together with newlines to get the desired output. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##K0gtyjH7/7@4NEmhvCixQEFDpbikKDMvXUdBpTwzpSRDU6GaSwEIoMJ6yfm5SRpQKb2s/Mw8DaWYPCVNrtr/IO0aKlqefnrpqSVA7VCWnmdeiaZecWLlf0cnZxdXN3cPTy9vH18//4DAoOCQ0LDwiMgoLlMA %} +sub wrap ($string, $width) { + $string.comb($width).join("\n") +} +{% endhighlight %} + +
+
+ +{% markdown %} +For the Perl 6 solution, I have not used an additional module, as all the +functionality are in the core namespace. I actually made a module in Perl 6 for +a less primitive wrapping functionality, called [`String::Fold`][string::fold]. + +In this solution, I use `comb` with the `$width` argument. This returns a list +of strings, each no longer than the given width, just like Python's +`textwrap.wrap`. I can then join these together with newlines as well to get +the same result. + +[string::fold]: https://modules.perl6.org/dist/String::Fold:cpan:TYIL +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### Designer Door Mat + +This challenge is more complex than previous challenges. The task at hand is to +"draw" a certain "design" as the output. For the input, you are given both a +height _y_ and a width _x_, however _x_ must always be _y_ × 3, so you can +ignore the second argument. + +This one is much simpler to explain using two examples. The first example is +the output if the input were `7 21`. +{% endmarkdown %} + +{% highlight text %} +---------.|.--------- +------.|..|..|.------ +---.|..|..|..|..|.--- +-------WELCOME------- +---.|..|..|..|..|.--- +------.|..|..|.------ +---------.|.--------- +{% endhighlight %} + +{% markdown %} +In the second example, the input is `11 33`. +{% endmarkdown %} + +{% highlight text %} +---------------.|.--------------- +------------.|..|..|.------------ +---------.|..|..|..|..|.--------- +------.|..|..|..|..|..|..|.------ +---.|..|..|..|..|..|..|..|..|.--- +-------------WELCOME------------- +---.|..|..|..|..|..|..|..|..|.--- +------.|..|..|..|..|..|..|.------ +---------.|..|..|..|..|.--------- +------------.|..|..|.------------ +---------------.|.--------------- +{% endhighlight %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##zZDNS8MwGMbv@SseMwbJlrbrehCEnWS3DS@CBxGpNFsCJQ1p5xD832s@Nh2I7GpyCHmf3/u8H/ZjUJ2pxnFyg@LQu@JNm0Kad9gkEKKk3qsBK2gzMKaNPQyM571ttX/58@KFk6NuBuWJEzpDRVTd7s45p3CGkqPAkhMywWNnERiy6xxabaRH4Wqzl6wUUcHc83cE/pjOvDZ1r2TvLRmL@MwbRctIfKuxYOonA7tI9E3xc/mQYV1A6bQPl2IKRjPqqYQL0PwzD/8fCx@7IHgcY6ubppVxAPLbMRZKSSxoqa8idV5xkfSn9eb@Ybum4gpOUslNd5Tur92FsMBCIPvfuxvHWyzLLw %} +#! /usr/bin/env python3 + +height = int((input().split())[0]) +width = height * 3 +half = int((height - 1) / 2) + +# Top half +for line in range(1, half + 1): + non_dashes = ((line * 2) - 1) + dashes = int((width - (non_dashes * 3)) / 2) + + print("%s%s%s" % ("-" * dashes, ".|." * non_dashes, "-" * dashes)) + +# Middle line +print("%s%s%s" % ( + "-" * (int(width / 2) - 3), + "WELCOME", + "-" * (int(width / 2) - 3) +)) + +# Lower half +for line in range(half, 0, -1): + non_dashes = ((line * 2) - 1) + dashes = int((width - (non_dashes * 3)) / 2) + + print("%s%s%s" % ("-" * dashes, ".|." * non_dashes, "-" * dashes)) +{% endhighlight %} + +
+
+ +{% markdown %} +I split the code up in a top half, middle line and lower half, to make it +easier to reason about. The `for` loops contain some logic to get the right +output on every line. I found out that `range` supports a third argument, +allowing me to count down with it as well, which was perfect for this +situation. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##zZBBTsMwEEX3PsXgdpEgxVFSqSwiVqiLSi1skFiiIE@xpeBEdtpQhZyDo3CAHix0UpKGSuzxypp5/8/XL9Bm87adXEG4dTZ80SZEs4OCxoy97WGqUL@qEm5her28Fy7b2kJUuZVOKEylWJoy6bhKy1IR9iM4fMLstFFptgkGG68HAoh8OHxBnDA2gce8AALZJrcQCfFLVTM4PvIyuQlk6hS6zuqZzsQ@eSUDM9qfQgXH30hIyfzhNKlcugde84DDey9vai4@RDc4S5sLhiesofBrLWWGkGmDbOzl9QnoFqWc@c3TYnX3sF7U8DfCu0ZWeYX23Il3UYovLO7QOvzX7bTtDcTRNw %} +#! /usr/bin/env perl6 + +my $height = $*IN.slurp.words.head.Int; +my $width = $height × 3; +my $half-height = ($height - 1) ÷ 2; + +# Top half +for 1..$half-height { + my $non-dashes = ($_ × 2) - 1; + my $dashes = ($width - ($non-dashes × 3)) ÷ 2; + + say "{"-" x $dashes}{".|." x $non-dashes}{"-" x $dashes}"; +} + +# Middle line +say "{"-" x (($width ÷ 2) - 3)}WELCOME{ "-" x (($width ÷ 2) - 3)}"; + +# Lower half +for (1..$half-height).reverse { + my $non-dashes = ($_ × 2) - 1; + my $dashes = ($width - ($non-dashes × 3)) ÷ 2; + + say "{"-" x $dashes}{".|." x $non-dashes}{"-" x $dashes}"; +} +{% endhighlight %} + +
+
+ +{% markdown %} +As usual, the code is functionally the same. I must admit I like the functional +style to get an `Int` from the first argument much more than the way I do it in +Python, though. + +A thing I learned is that the `..` operator that generates a sequence does not +have a way to make a sequence that counts down, so I had to use `.reverse` on a +sequence that counts up. I had expected this to Just Work as I expected and +count down if the left hand side would be larger than the right hand side. + +You may notice some fancy Unicode characters in the source, namely `×` for +multiplication, and ÷ for division. Perl 6 allows Unicode characters in the +source files, which can oftentimes lead to prettier code. In this particular +instance, there's no big difference in code readability, though. And for those +who don't yet have a modern editor that can make Unicode characters, do not +worry, as the ASCII equivalents (`*` and `/` respectively) still work as well. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +### String Formatting + +In this challenge, you are to produce a table with four columns. The columns +should contain the decimal, octal, hexadecimal and binary values of the row +numbers. The function receives an int _number_. The table should contain that +many rows, starting with row number 1. +{% endmarkdown %} + +
+
+
+
+ +{% highlight python3 tio=https://tio.run/##jZFNCoMwEIX3nmIQhIQG0XYn9CwSTawpJoYYqVJ6dht/W7uQDlll3vveTKJ7W9bqMgyMF6CNUDYtaiOptZwh1cqMG5x44ErSLn0IZku4QsUV8p9Rkr38cJavWuxNYncJAoQCQ9WNo5jA3IcTxAtvLMZzIWnliI72YQkcmnvbWLRl4s1S53Y1JPV/lpJ3dJeUdDtjqzU36ACQCUVNv3iz49DNND0m8oMG1uNDAGgZhMyLkO/hyBKE8fD7EyNKKN1ahF33HL0B %} +def print_formatted(number): + max_width = len("{0:b}".format(number)) + + for i in range(1, number + 1): + decimal = "{0}".format(i).rjust(max_width) + octal = "{0:o}".format(i).rjust(max_width) + hexadecimal = "{0:x}".format(i).upper().rjust(max_width) + binary = "{0:b}".format(i).rjust(max_width) + + print("%s %s %s %s" % (decimal, octal, hexadecimal, binary)) +{% endhighlight %} + +
+
+ +{% markdown %} +In the Python 3 solution I first calculate the max width I need to take into +account. Then I loop from 1 until _number_ to get the right amount of rows. +Each iteration, I format the number correctly, and then print it out using a +printf format string. + +The hardest part of this challenge was to get formatting right the way +Hackerrank wanted it. But I guess that was the entire point of the challenge. +{% endmarkdown %} + +
+
+
+
+ +{% highlight perl6 tio=https://tio.run/##XY9NCsIwEIX3PcUQIiRiB1tEBPEA3bhxK0iq0VZMWpIUK1KvXmNb/HurGWbeN29KaS7ztrVVCqXJtQuPhVHCOXkARnWlUmk43APwUjegStThNT@4DFYwjDEVVrKY48YZ3GfC2OV7vYeF1nn0yVsYGd0/jMYSqGuYcTwXuWYECIcHkK0my6BDeDtEiMOhIcZLv2Dskh8Z3U2A7vo8C/6po/lXE3Pe52uCpv17mdFxssaTdJhox9t4@gQ %} +sub print-formatted ($number) { + my $max-width = $number.base(2).Str.chars; + my $format-string = ("%{$max-width}s" xx 4).join(" ") ~ "\n"; + + for 1..$number { + $format-string.printf($_, $_.base(8), $_.base(16), $_.base(2)); + } +} +{% endhighlight %} + +
+
+ +{% markdown %} +The Perl 6 solution starts of the same, in that it first calculates the max +width I need to take into account. Next, however, I generate the format string +using the `$max-width` to make the `printf` subroutine pad it for me. The `xx` +operator makes a total of 4 such strings, and puts them into a list, which I +can then `join` together with a space character, and add a `\n` at the end of +it (the `~` operator is for string concatenation). + +I'm assuming something similar is possible in Python 3 as well, and I would +like to have an example so I can compare it more fairly. + +In the Perl 6 solution I am also able to make use of the `base` method to +convert the numbers into the right base, something I could not find for Python +3. +{% endmarkdown %} + +
+
+
+
+ +{% markdown %} +## Wrap-up + +This time I did not do all of the challenges, as the post would probably get +too long. I still did 8 of them, and might do the rest of the string challenges +in a later part anyway. + +I still find Perl 6 to produce much cleaner code, which is shown best with the +first challenge. In Perl 6 (`$line.split(" ").join("-")`), I can read from left +to right to see what I'm doing: I have a `$line`, which I split, and then join. +In the Python variant (`"-".join(line.split(" "))`), it is much less clear what +the actual item I'm working on is, as it's hidden inbetween the `join` and +`split` calls. + +Of course, I'm still not an expert on Python 3 code, so I'm sure that there are +many parts that could be written in a cleaner fashion. I'm still open for +feedback to improve my Python 3 skills (hence I'm publishing these posts), so +please let me know if you know better ways to solve some challenges. +{% endmarkdown %} -- cgit v1.1