Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

read strings from console without for loop

Tags:

f#

Is there any elegant functional way to read N strings from console input? F# for fun and profit recommends to avoid for-loops, so i used recursion but it looks ugly and long.

Code description: I need to read several strings from console (exact number is specified in first line of input from console), concatenate them and convert to array of integers.

let rec recReadline n =
    match n with
        | 0 -> ""
        | _ -> let x = n - 1
               " " + Console.ReadLine() + recReadline x 

let getArrayOfIntFromConsole = 
    let x = Console.ReadLine() |> int |> recReadline
    let trimmedString = x.Trim()
    let numArray = trimmedString.Split ' ' |> Array.map(int)
    numArray

I'm learning f#, sorry for noob question.

Update1

Thanks for replies! This was task from hacker rank: https://www.hackerrank.com/challenges/diagonal-difference. At first i decided to separate input and algorithm logic and created this post. I was not clear enough describing context of the question and was advised to use Array.Init. It did not help me because input string consists of many integers separated by space. I marked one reply with Array.Init as correct answer because it was correct answer for my poor formulated question.

I decided to read console and compute in one function and it worked ok for me. My final code:

open System

let rec recDiagDif recCounter primaryDiagSum secondDiagSum =
    match recCounter with
        | 0 -> primaryDiagSum - secondDiagSum |> abs
        | _ -> let arrayInt = Console.ReadLine().Split ' ' |> Array.map(int)
               recDiagDif (recCounter-1)
                          (primaryDiagSum + arrayInt.[arrayInt.Length - recCounter])
                          (secondDiagSum + arrayInt.[recCounter-1])

[<EntryPoint>]
let main argv =
    let matrixSize = Console.ReadLine() |> int
    printf "%A" (recDiagDif matrixSize 0 0)
    0

If you know how to improve code, please feel free to comment.

like image 411
corund Avatar asked Jun 19 '16 17:06

corund


2 Answers

I would be inclined to suggest keeping the console input as some kind of collection, rather than converting to a flat string only to then split again on whitespace.

let readNLines n =  Array.init n (fun _ -> Console.ReadLine())

let getArrayOfIntFromConsole() = 
    let lines = Console.ReadLine() |> int |> readNLines
    let numArray = lines |> Array.map(int)
    numArray
like image 193
TheInnerLight Avatar answered Sep 22 '22 08:09

TheInnerLight


You could do something like this:

open System

let getArrayOfIntFromConsole () = 
    let readLines n = Array.init n (fun _ -> System.Console.ReadLine ())
    Console.ReadLine () |> int |> readLines |> Array.map int

Demo (FSI):

> getArrayOfIntFromConsole ();;
3
1
42
1337
val it : int [] = [|1; 42; 1337|]
like image 29
Mark Seemann Avatar answered Sep 25 '22 08:09

Mark Seemann