有没有一种方法可以在Kotlin中使用初始化函数构造一个HashSet?

要从Facebook Hacker Cup 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中的大小为n和初始化函数的HashSet

更新:标准Kotlin库中是否存在一种方法?

您始终可以使用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) } 

由于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 } 

正如@miensol指出的那样, HashSet初始化仅限于JDK提供的构造函数。 Kotlin添加了一个hashSetOf函数,它初始化一个空的HashSet ,然后将指定的元素添加到它。

为了避免首先将值读入数组,可以使用kotlin.Sequence谁的“价值评估懒惰”:

 fun BufferedReader.readStars(n: Int): Set<Star> { return lineSequence().take(n).map { val (l1, l2) = it.split(" ").map { it.toInt() } Star(l1, l2) }.toHashSet() } 

这似乎是你问一个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字符串自己拆分substring

如果你做了一个分割,那么当你想要分割一个char时,请使用split(char)而不是split(String)