要从Facebook Hacker Cup's 2016 Boomerang Constelations问题中的文件中读取星星,可以定义以下扩展功能:
fun BufferedReader.readStars(n: Int): Set<Star> {
return Array(n) {
val (l1, l2) = readLine().split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
代码是紧凑的,但首先将值读入数组,然后转换为HashSet
。有没有办法在Kotlin中直接初始化HashSet
大小为n
和初始化函数?
更新:标准Kotlin库中是否存在现有方式?
答案 0 :(得分:7)
您始终可以使用apply
来就地初始化对象:
HashSet<Star>(n).apply {
repeat(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
put(Star(l1, l2))
}
}
如果每次都太不方便,请写一个扩展功能:
inline fun <T> createHashSet(n : Int, crossinline fn: (Int) -> T) = HashSet<T>(n).apply {
repeat(n) { add(fn(it)) }
}
用法:
createHashSet<Star>(n) {
val (l1, l2) = readLine()!!.split(' ').map { it.toInt() }
Star(l1, l2)
}
答案 1 :(得分:5)
由于HashSet
是一个java类,因此您只能以JDK提供的方式初始化它。
虽然Kotlin运行时没有帮助方法,但很容易自己编写:
public fun <T> hashSetOf(size: Int, initializer: (Int) -> T): HashSet<T> {
val result = HashSet<T>(size)
0.rangeTo(size - 1).forEach {
result.add(initializer(it))
}
return result
}
答案 2 :(得分:1)
正如@miensol指出HashSet
初始化仅限于JDK提供的构造函数。 Kotlin添加了一个hashSetOf
函数,用于初始化空HashSet
,然后将指定的元素添加到其中。
为避免首先将数值读入数组,您可以使用kotlin.Sequence
懒散地评估&#34;&#34;值
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().take(n).map {
val (l1, l2) = it.split(" ").map { it.toInt() }
Star(l1, l2)
}.toHashSet()
}
答案 3 :(得分:1)
好像你在问一个XY问题(http://xyproblem.info/)。您真的想知道如何以最有效的方式编写readStars
,而是询问HashSet
。我认为@ mfulton26也会根据被问到的内容回答你的问题。
以下是“如何以最有效的方式撰写此内容”的答案:
您有两种选择。首先,在最后自动关闭流的版本:
fun BufferedReader.readStars(n: Int): Set<Star> {
return use {
lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx + 1).toInt())
}.toSet()
}
}
第二,没有的版本:
fun BufferedReader.readStars(n: Int): Set<Star> {
return lineSequence().map { line ->
val idx = line.indexOf(' ')
Star(line.substring(0, idx).toInt(), line.substring(idx+1).toInt())
}.toSet()
}
两个版本都没有创建数组,也没有创建数据副本。它们通过一个序列流式传输数据,该序列创建Set并直接填充它。
其他说明
如果您真的关心分配和性能,则无需使用拆分。只需使用indexOf(char)
并使用substring
自行拆分字符串。
如果您进行拆分,那么当您希望拆分split(char)
时,请使用split(String)
而不是char