Ответ 1
Вот примеры A + B в котлинском чтении со стандартного ввода:
fun main() {
val (a, b) = readLine()!!.split(' ')
println(a.toInt() + b.toInt())
}
или же
fun main(vararg args: String) {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
или же
fun readInts() = readLine()!!.split(' ').map { it.toInt() }
fun main(vararg args: String) {
val (a, b) = readInts()
println(a + b)
}
или же
import java.util.Scanner
fun main() {
val input = Scanner(System.'in')
val a = input.nextInt()
val b = input.nextInt()
println(a + b)
}
или же
with(Scanner(System.'in')) {
val a = nextInt()
val b = nextInt()
println(a + b)
}
Конкурентное программирование
Обязательно прочтите вступительное слово: https://kotlinlang.org/docs/tutorials/competitive-programming.html
Вот (вдохновленный статьей) расширенный набор вспомогательных функций для чтения всех возможных типов, списков, массивов, 2d-массивов и т. Д.:
private fun readln() = readLine()!!
private fun readlnByte() = readln().toByte()
private fun readlnShort() = readln().toShort()
private fun readlnInt() = readln().toInt()
private fun readlnLong() = readln().toLong()
private fun readlnFloat() = readln().toFloat()
private fun readlnDouble() = readln().toDouble()
private fun readlnBigInt(radix: Int = 10) = readln().toBigInteger(radix)
private fun readlnBigDecimal() = readln().toBigDecimal()
private fun lineSequence(limit: Int = Int.MAX_VALUE) = generateSequence { readLine() }.constrainOnce().take(limit)
private fun readlnStrings() = readln().split(' ')
private fun readlnBytes() = readlnStrings().map { it.toByte() }
private fun readlnShorts() = readlnStrings().map { it.toShort() }
private fun readlnInts() = readlnStrings().map { it.toInt() }
private fun readlnLongs() = readlnStrings().map { it.toLong() }
private fun readlnFloats() = readlnStrings().map { it.toFloat() }
private fun readlnDoubles() = readlnStrings().map { it.toDouble() }
private fun readByteArray() = readlnStrings().run { ByteArray(size) { get(it).toByte() } }
private fun readShortArray() = readlnStrings().run { ShortArray(size) { get(it).toShort() } }
private fun readIntArray() = readlnStrings().run { IntArray(size) { get(it).toInt() } }
private fun readLongArray() = readlnStrings().run { LongArray(size) { get(it).toLong() } }
private fun readFloatArray() = readlnStrings().run { FloatArray(size) { get(it).toFloat() } }
private fun readDoubleArray() = readlnStrings().run { DoubleArray(size) { get(it).toDouble() } }
private fun readlnByteArray(n: Int) = ByteArray(n) { readlnByte() }
private fun readlnShortArray(n: Int) = ShortArray(n) { readlnShort() }
private fun readlnIntArray(n: Int) = IntArray(n) { readlnInt() }
private fun readlnLongArray(n: Int) = LongArray(n) { readlnLong() }
private fun readlnFloatArray(n: Int) = FloatArray(n) { readlnFloat() }
private fun readlnDoubleArray(n: Int) = DoubleArray(n) { readlnDouble() }
private fun readByteArray2d(rows: Int, cols: Int) = Array(rows) { readByteArray().also { require(it.size == cols) } }
private fun readShortArray2d(rows: Int, cols: Int) = Array(rows) { readShortArray().also { require(it.size == cols) } }
private fun readLongArray2d(rows: Int, cols: Int) = Array(rows) { readLongArray().also { require(it.size == cols) } }
private fun readIntArray2d(rows: Int, cols: Int) = Array(rows) { readIntArray().also { require(it.size == cols) } }
private fun readFloatArray2d(rows: Int, cols: Int) = Array(rows) { readFloatArray().also { require(it.size == cols) } }
private fun readDoubleArray2d(rows: Int, cols: Int) = Array(rows) { readDoubleArray().also { require(it.size == cols) } }
private fun isWhiteSpace(c: Char) = c in " \r\n\t"
// JVM-only targeting code follows next
// readString() via sequence is still slightly faster than Scanner
private fun readString() = generateSequence { System.'in'.read().toChar() }
.dropWhile { isWhiteSpace(it) }.takeWhile { !isWhiteSpace(it) }.joinToString("")
private fun readByte() = readString().toByte()
private fun readShort() = readString().toShort()
private fun readInt() = readString().toInt()
private fun readLong() = readString().toLong()
private fun readFloat() = readString().toFloat()
private fun readDouble() = readString().toDouble()
private fun readBigInt(radix: Int = 10) = readString().toBigInteger(radix)
private fun readBigDecimal() = readString().toBigDecimal()
private fun readBytes(n: Int) = generateSequence { readByte() }.take(n)
private fun readShorts(n: Int) = generateSequence { readShort() }.take(n)
private fun readInts(n: Int) = generateSequence { readInt() }.take(n)
private fun readLongs(n: Int) = generateSequence { readLong() }.take(n)
private fun readFloats(n: Int) = generateSequence { readFloat() }.take(n)
private fun readDoubles(n: Int) = generateSequence { readDouble() }.take(n)
Остерегайтесь, что Сканер работает несколько медленно. Это может быть важно в некоторых случаях, например, в конкурентном программировании, где выполнение программы на больших входах можно ускорить в два раза, просто заменив Scanner на обычную readLine. Даже моя неоптимальная реализация readString()
использованием последовательности выполняется несколько быстрее. Он позволяет читать входные токены до следующего пробела, в отличие от встроенного в Kotlin readLine()
.
Я надеюсь, что когда-нибудь в Kotlin stdlib появится краткая, кроссплатформенная, производительная, универсальная поддержка парсинга и ввода файлов. Как readInt
, readLong
и т.д. Глобальные и функции расширения Reader
. Это было бы очень полезно не только для конкурентного программирования, но и для изучения Kotlin в качестве первого языка. Концепция чтения числа не должна требовать предварительного объяснения коллекций, лямбд и монад.
бонус
Иногда вы начинаете с консольного ввода/вывода, но затем необходимо переключиться на файлы. Становится слишком утомительным начинать каждый вызов чтения или записи переменной потока файла.
Вот мир волшебства Kotlin, который позволяет просто обернуть неизмененный консольный код парой строк, чтобы заставить его читать и записывать в файлы, также гарантируя, что они закрыты должным образом:
fun <T : Closeable, R> T.useWith(block: T.() -> R): R = use { with(it, block) }
File("a.in").bufferedReader().useWith {
File("a.out").printWriter().useWith {
val (a, b) = readLine()!!.split(' ').map(String::toInt)
println(a + b)
}
}
Scanner(File("b.in")).useWith {
PrintWriter("b.out").useWith {
val a = nextInt()
val b = nextInt()
println(a + b)
}
}
Строки переноса могут быть быстро закомментированы, когда возникает необходимость переключиться обратно на консоль.