Как получить несколько строк stdin Swift HackerRank?

Я только что опробовал вызов HackerRank, и если вопрос дает вам x строк ввода, то положить x строк let someVariable = readLine() просто не режет его, потому что есть много тестовых примеров, которые снимают больше ввод в код, который мы пишем, поэтому строчная кодированная readLine() для каждой строки ввода не будет летать.

Есть ли способ получить несколько строк ввода в одну переменную?

Ответы

Ответ 1

Для кого-то еще, кто впервые пытается попробовать HackerRank, вам может понадобиться знать пару вещей, которые вы, возможно, никогда не встречали. Я только недавно узнал об этом волшебстве, называемом командой readLine(), которая является родной функцией в Swift.

Когда система HackerRank выполняет ваш код, она передает ваши строки кода ввода, и это способ получить этот вход.

let line1 = readLine()
let line2 = readLine()
let line3 = readLine()

line1 теперь получает значение первой строки ввода, указанной в вопросе (или доставляется к вашему коду одним из тестовых случаев), причем строка 2 является второй и т.д.

Ваш код может работать просто отлично, но может завершиться неудачей в связке других тестовых случаев. Эти тестовые примеры не отправляют ваш код столько же строк ввода. Здесь пища для размышлений:

var string = ""

while let thing = readLine() {
string += thing + " "
}

print(string)

Теперь строковая переменная содержит все входные данные, которые необходимо было получить (в данном случае это строка).

Надеюсь, что кто-то поможет

:)

Ответ 2

Определенно, вы не должны этого делать:

while let readString = readLine() {
    s += readString
}

Это потому, что Swift будет ожидать входную строку (от readLine) навсегда и никогда не завершится, в результате чего ваше приложение умрет с помощью тайм-аута.

Вместо этого вы должны думать в цикле for, предполагая, что знаете, сколько строк вам нужно читать, что обычно происходит в HackerRank;)

Попробуйте что-то вроде этого:

let n = Int(readLine()!)! // Number of test cases
for _ in 1 ... n { // Loop from 1 to n
    let line = readLine()! // Read a single line
    // do something with input
}

Если вы знаете, что каждая строка является целым числом, вы можете использовать это:

let line = Int(readLine()!)!

Или, если вы знаете, что каждая строка представляет собой массив целых чисел, используйте это:

let line = readLine()!.characters.split(" ").map{ Int(String($0))! }

Или если каждая строка представляет собой массив строк:

let line = readLine()!.characters.split(" ").map{ String($0) }

Надеюсь, это поможет.

Ответ 3

Для новой версии, чтобы получить массив чисел, разделенных пробелом

let numbers = readLine()!.components(separatedBy: [" "]).map { Int($0)! }

Ответ 4

Используя readLine() и AnyGenerator для построения массива String входных строк std

readLine() будет считываться из стандартного ввода по очереди до тех пор, пока не будет нажата EOF, после чего он вернет nil.

Возвращает Character чтение со стандартного ввода до конца текущей линии или до достижения EOF или nil, если EOF уже достиг.

Это довольно аккуратно, так как делает readLine() идеальным кандидатом для генерации последовательности, используя AnyGenerator initializer init(body:), который рекурсивно (как next()) вызывает body, завершая в случае, если body равно nil.

AnyGenerator

init(body: () -> Element?)

Создайте экземпляр GeneratorType, метод next вызывает bodyи возвращает результат.

При этом нет необходимости фактически предоставлять количество строк, которые мы ожидаем от стандартного ввода, и, следовательно, мы можем поймать весь вход со стандартного ввода, например. в массив String, где каждый элемент соответствует строке ввода:

let allLines = AnyGenerator { readLine() }.map{ $0 }
    // type: Array<String>

После этого мы можем работать с массивом String для применения любых операций, необходимых для решения заданной задачи (/HackerRank task).

// example standard input
4 3
<tag1 value = "HelloWorld">
<tag2 name = "Name1">
</tag2>
</tag1>
tag1.tag2~name
tag1~name
tag1~value

/* resulting allLines array:
   ["4 3", "<tag1 value = \"HelloWorld\">", 
    "<tag2 name = \"Name1\">", 
    "</tag2>", 
    "</tag1>", 
    "tag1.tag2~name", 
    "tag1~name", 
    "tag1~value"] */

Ответ 5

Недавно я обнаружил аккуратный трюк, чтобы получить определенное количество строк. Я собираюсь предположить, что первая строка дает вам количество строк:

guard let count = readLine().flatMap({ Int($0) }) else { fatalError("No count") }

let lines = AnyGenerator{ readLine() }.prefix(count)

for line in lines {

}