有没有办法在Kotlin中用initializator函数构造HashSet?

时间:2016-01-12 08:25:52

标签: kotlin

要从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库中是否存在现有方式?

4 个答案:

答案 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