Implementing a Hacker Rank challenge
The problem is as follows:
Given a list, repeat each element in the list N amount of times.
The first line contains the integer S where S is the number of times you need to repeat the elements. The next X lines each contain an integer. These are the X elements in the array.
Output each element of the original list S times, each on a separate line. You have to return the list/vector/array of S * X integers. The relative positions of the values should be the same as the original list provided in the input.
The following example input and output is provided:
3 1 2 3 4
1 1 1 2 2 2 3 3 3 4 4 4
This is the implementation I wrote. One of my aims was to write an implementation that was not the most concise code possible so that it is more approachable. Unlike many other implementations I saw this one has validation. A number is required as the first line and the program terminates if it is not. It also simply ignores any non-numeric input later on.
I feel there is a lot of room for improvement but I need a deeper understanding of both the syntax and idiomatic F# in order to improve it. For example, I would ideally use
Option.bind to refactor away the nested pattern match in the
However I did make sure to separate the pure functions from the impure side effects and I/O, with the
parseNumber function. Of course, separating them is simply a good practice anyway. Functional programming really does promote many beneficial values.
open System let parseNumber (number: string) = match Int32.TryParse number with | (true, number) -> Some number | _ -> None let readFirstLine = parseNumber (Console.ReadLine()) let rec readLines accumulatedLines = let line = Console.ReadLine() let parsed = parseNumber line match line with | null | "" -> Seq.rev accumulatedLines | _ -> match parsed with | Some number -> readLines (number :: accumulatedLines) | None -> readLines accumulatedLines [<EntryPoint>] let main args = let count = readFirstLine match count with | Some count -> let numbers = readLines  Seq.iter (fun number -> for _ in 1 .. count do printfn "%d" number) numbers 0 | None -> printfn "First line must be a number" 1
A rant about Hacker Rank’s input mechanism
Unfortunately Hacker Rank chose to implement a very awkward and unnecessarily painful input mechanism. It writes to
stdin but in a psuedo-unbounded fashion. That is, the number of lines of input often varies while also never providing a clean mechanism for signalling when input is complete. That isn’t strictly true, as it does actually close
stdin but… why make it so much harder than it has to be?
Firstly, several of the other supported languages provide a “template” empty function where reading
stdin and writing to
stdout are taken care of for you - the function is then a pure function. The Hacker Rank F# option does not provide this template and so we must write extra code.
Secondly and more importantly, why does it not simply write a blank line to
stdin? Think of all those programming exercises that go something like “if the user enters a blank line or types
quit terminate the program”. Hacker Rank could instead write a blank line but it does not. This leads to the code being probably double what it really needs to be. If you run the above code locally you’ll see I took care of both approaches;
null for when
stdin has been closed and
"" for when a user types an empty line.