Hackerrank solutions: Python 3 and Perl 6 (part 2)

As a continuation of the previous part 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 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.

Disclaimer Once again I'd like to make clear I'm trying to stick to the original Hackerrank challenges by not using any imports not specifically used in the original challenge. If you have suggestions for Python 3 or Perl 6 modules to make a given task easier, I still appreciate them, but I won't update my solutions to use a module.

Challenges

String Split and Join This challenge involves a string containing spaces, where the spaces are to be replaced with dashes ( - ) instead. def split_and_join ( line ): return "-" . join ( line . split ( " " )) Run this code sub split-and-join ( $line ) { $line . split ( " " ). join ( "-" ) } Run this code 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 . def print_full_name ( a , b ): print ( "Hello %s %s ! You just delved into python." % ( a , b )) Run this code sub print-full-name ( $a , $b ) { say "Hello $a $b! You just delved into Perl 6." } Run this code 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. def mutate_string ( string , position , character ): chars = list ( string ) chars [ position ] = character return "" . join ( chars ) Run this code sub mutate-string ( $string , $position , $character ) { my @list = $string . comb ; @list [ $position ] = $character ; @list . join ; } Run this code 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. 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 Run this code sub count-substring ( $string , $sub-string ) { elems $string ~~ m:overlap/$sub-string/ } Run this code 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" . 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 ]) Run this code sub MAIN { my $s = $*IN . get ; say so $s ~~ /<alnum>/ ; say so $s ~~ /<alpha>/ ; say so $s ~~ /<digit>/ ; say so $s ~~ /<lower>/ ; say so $s ~~ /<upper>/ ; } Run this code 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. import textwrap def wrap ( string , max_width ): return "

" . join ( textwrap . wrap ( string , max_width )) Run this code sub wrap ( $string , $width ) { $string . comb ( $width ). join ( "

" ) } Run this code 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 . ---------.|.--------- ------.|..|..|.------ ---.|..|..|..|..|.--- -------WELCOME------- ---.|..|..|..|..|.--- ------.|..|..|.------ ---------.|.--------- In the second example, the input is 11 33 . ---------------.|.--------------- ------------.|..|..|.------------ ---------.|..|..|..|..|.--------- ------.|..|..|..|..|..|..|.------ ---.|..|..|..|..|..|..|..|..|.--- -------------WELCOME------------- ---.|..|..|..|..|..|..|..|..|.--- ------.|..|..|..|..|..|..|.------ ---------.|..|..|..|..|.--------- ------------.|..|..|.------------ ---------------.|.--------------- #! /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 )) Run this code #! /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}" ; } Run this code 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. 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 )) Run this code sub print-formatted ( $number ) { my $max-width = $number . base ( 2 ). Str . chars ; my $format-string = ( "%{$max-width}s" xx 4 ). join ( " " ) ~ "

" ; for 1 .. $number { $format-string . printf ( $_ , $_ . base ( 8 ), $_ . base ( 16 ), $_ . base ( 2 )); } } Run this code

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.