¿Hay alguna manera de build un HashSet con function de initialization en Kotlin?

Para leer las estrellas de un file en el problema de constelaciones Boomerang 2016 de Facebook Hacker Cup , se puede definir la siguiente function de extensión:

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

El código es compacto, pero los valores se leen primero en una matriz y luego se convierten en un HashSet . ¿Hay alguna manera de inicializar directamente un HashSet con el tamaño de n y la function de initialization en Kotlin?

ACTUALIZACIÓN: ¿Hay una forma existente en las librerías estándar de Kotlin?

Siempre puede usar apply para inicializar objects en el lugar:

 HashSet<Star>(n).apply { repeat(n) { val (l1, l2) = readLine()!!.split(' ').map { it.toInt() } put(Star(l1, l2)) } } 

Si eso también es demasiado inconveniente, escriba cada vez, escriba una function de extensión:

 inline fun <T> createHashSet(n : Int, crossinline fn: (Int) -> T) = HashSet<T>(n).apply { repeat(n) { add(fn(it)) } } 

Uso:

 createHashSet<Star>(n) { val (l1, l2) = readLine()!!.split(' ').map { it.toInt() } Star(l1, l2) } 

Debido a que HashSet es una class Java, solo puede inicializarlo de la forma indicada por JDK.

Si bien no hay un método de ayuda en el time de ejecución de Kotlin , es fácil escribirlo usted mismo así:

 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 } 

Como @miensol ha señalado, la initialization de HashSet está limitada a los constructores puestos a disposition por el JDK. Kotlin ha agregado una function hashSetOf que inicializa un HashSet vacío y luego le agrega los elementos especificados.

Para evitar la primera lectura de los valores en una matriz, puede usar un kotlin.Sequence los "valores evaluados perezosamente":

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

Parece que estás haciendo una pregunta XY ( http://xyproblem.info/ ). Realmente desea saber cómo escribir readStars de la manera más eficiente, pero en su lugar pregunta acerca de HashSet . Creo que @ mfulton26 también responde su pregunta dependiendo de lo que se le pregunte.

Aquí está la respuesta para "cómo escribo esto de la manera más eficiente":

Tienes dos opciones. Primero, una versión que cierra automáticamente la secuencia al final:

 fun BuffenetworkingReader.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() } } 

Y segundo, una versión que no:

 fun BuffenetworkingReader.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() } 

Ninguna versión crea una matriz, ni hacen copys de datos. Transmiten los datos a través de una secuencia que crea el set y lo llena directamente.

Otras notas

No es necesario utilizar split si realmente está preocupado por las asignaciones y el performance. Solo use indexOf(char) y divida la cadena usted mismo usando substring .

Si haces una split, entonces usa split(char) not split(String) cuando estás buscando dividir en un char

  • Usando las constantes de kotlin en la expresión del interruptor java
  • ¿Cómo puedo enmascarar una contraseña con Anko?
  • Android Architecture Components Room ViewModel CompleteableFormAction
  • cómo comstackr kotlin en el proyecto web eclipse maven
  • Kotlin: creación de una list mutable con elementos repetitivos
  • Regex Match en una string
  • ¿Por qué hay una diferencia entre los constructores de coroutine para CompletableFuture y ListenableFuture?
  • TornadoFX: Type-Safe CSS con otras bibliotecas
  • Completion Handler Android Kotlin
  • Realm, findAllSorted y distinct
  • Realm executeTransactionAsync no escribe datos en DB