Как получить несколько строк 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 {
}