2016-06-19 2 views
3

Есть ли элегантный функциональный способ чтения N строк из ввода с консоли? F# for fun and profit рекомендует избегать циклов, поэтому я использовал рекурсию, но она выглядит уродливой и длинной.читать строки из консоли без цикла

Описание кода: Мне нужно прочитать несколько строк из консоли (точное число указано в первой строке ввода с консоли), объединить их и преобразовать в массив целых чисел.

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 

Я изучаю f #, извините за вопрос noob.

Update1

Спасибо за ответы! Это была задача от хакерского ранга: https://www.hackerrank.com/challenges/diagonal-difference. Сначала я решил разделить логику ввода и алгоритма и создал этот пост. Я не был достаточно ясен, описывая контекст вопроса, и мне было предложено использовать Array.Init. Это не помогло мне, потому что входная строка состоит из множества целых чисел, разделенных пробелом. Я отметил один ответ с помощью Array.Init как правильный ответ, потому что это был правильный ответ на мой плохо сформулированный вопрос.

Я решил прочитать консоль и вычислить в одной функции, и это сработало нормально для меня. Мой окончательный код:

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 

Если вы знаете, как улучшить код, пожалуйста, не стесняйтесь комментировать.

+0

пахнет очень похоже на https://courses.edx.org/courses/course- v1: Microsoft + DEV207.1x + 1T2016/info ... –

+0

нет, это была задача из hr: https://www.hackerrank.com/challenges/diagonal-difference – corund

ответ

4

я был бы склонен предположить, сохраняя консольный ввод как своего рода коллекцию, а не преобразовывать к плоской строке, чтобы затем снова разделить на пробелы.

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

let getArrayOfIntFromConsole() = 
    let lines = Console.ReadLine() |> int |> readNLines 
    let numArray = lines |> Array.map(int) 
    numArray 
1

Вы можете создать бесконечную последовательность, которая подается из Console.ReadLine и просто взять первые n элементов, как так

let readNStrings n =      
    fun _ -> Console.ReadLine() 
    |> Seq.initInfinite 
    |> Seq.take n 
+2

Я не уверен, что это хорошая идея, ленивый оценка и IO делают опасную комбинацию для опытного разработчика lopers, не считая людей, новых для F #. Нет никакой гарантии, сколько раз 'Console.ReadLine()' выполняется в этом примере или даже когда это делается. – TheInnerLight

3

Вы могли бы сделать что-то вроде этого:

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|] 
Смежные вопросы