Consejos para jugar al golf en Kotlin

22

Dado el reciente anuncio de Google del soporte oficial de Kotlin para el desarrollo de Android, pensé que podría ser oportuno sondear a la comunidad para obtener algunos consejos de golf increíbles para este lenguaje JVM relativamente nuevo.

Kotlin incluye una combinación única de características entre sus hermanos JVM que lo hace potencialmente atractivo para el golf:

Entonces, ¿cómo exprimo los últimos bytes de mi programa Kotlin? Un consejo por respuesta, por favor.

Tyler MacDonell
fuente
2
¿Habría interés en un lenguaje de golf que acorte algunos de los nombres más largos de Kotlin, pero que no agregue muchos extras (al menos inicialmente)? Estoy pensando en hacer 1 letra común, hacer que el recuento de caracteres de la cadena sea más corto y agregar cadenas de una sola letra con solo 1 comilla.
jrtapsell
* Funciones comunes
jrtapsell
Parece que el interés en el golf de Kotlin no es tan alto :( data.stackexchange.com/codegolf/query/793250/top-kotlin-golfers
jrtapsell
¡Planeo comenzar a enviar más soluciones de Kotlin! También tendré que revisar ese proyecto tuyo.
Tyler MacDonell

Respuestas:

4

Funciones de extensión

Las funciones de extensión realmente pueden ayudar a reducir los nombres de los métodos integrados, y las cadenas de ellos, un ejemplo podría ser:

fun String.c() = this.split("").groupingBy{it}.eachCount()

pero esto solo ayuda si:

A) La llamada es lo suficientemente larga como para cancelar la definición.

B) La llamada se repite

Uso de lambdas en lugar de métodos.

Lambdas puede regresar sin usar la palabra clave return, guardando bytes

KotlinGolfer

Un proyecto que comencé aquí que toma un bonito código de Kotlin y da publicaciones con pruebas y enlaces TIO automáticamente

jrtapsell
fuente
4

Usar en +lugar detoString

Como cabría esperar, Stringsobrecarga al +operador para la concatenación de cadenas, de esta manera.

print("Hel" + "lo")

Sin embargo, revisar los documentos nos dice que acepta Any?, no solo String. Como se dijo:

Devuelve una cadena obtenida concatenando esta cadena con la representación de cadena del otro objeto dado.

En otras palabras, String + anythingasegúrese de llamar .toString()al lado derecho antes de concatenar. Esto nos permite acortar it.toString()a ""+it, un enorme ahorro de 8 bytes en el mejor y en el peor de 6 bytes.


Usar en foldlugar dejoinToString

En relación con lo anterior, si está llamando mapy luego joinToString, puede acortar eso usando en su foldlugar.

list.map{it.repeat(3)}.joinToString("")
list.fold(""){a,v->a+v.repeat(3)}
caracol_
fuente
TIL fold es una cosa, agradable
Quinn
1

Definiendo Int en params

Es probable que esto tenga algunos casos de uso bastante específicos en los que puede valer la pena, pero en una pregunta reciente que hice al golf descubrí que podía ahorrar algunos bytes definiendo mi variable como parámetros opcionales en lugar de definirlos en la función.

Ejemplo de mi respuesta a esta pregunta:

variable definitoria en la función:

fun String.j()={var b=count{'-'==it}/2;var a=count{'/'==it};listOf(count{'o'==it}-a,a-b,b)}

definiendo variables como params:

fun String.j(b:Int=count{'-'==it}/2,a:Int=count{'/'==it})=listOf(count{'o'==it}-a,a-b,b)

porque var a=tiene la misma longitud ya a:Int=que será el mismo número de bytes para definirlos (este es solo el caso Int) sin embargo, dado que ahora solo tengo 1 línea en la función, puedo descartar {}y también descarto una sola ;(la otra es reemplazado con a ,)

Entonces, si hay funciones que requieren definir un Int, y sería un trazador de líneas 1 si no definió el int en la función, entonces hacerlo como parámetro ahorrará un par de bytes

Quinn
fuente
0

La tofunción infija

Hay una función infija estándar llamada toque crea Pairs de dos valores. Se usa comúnmente mapOf()para definir Maps, pero potencialmente puede ser mucho más corto que el Pair()constructor.

Pair(foo,bar)   //constructor
foo to bar      //best case 
(foo)to(bar)
((foo)to(bar))  //worst case
caracol_
fuente
0

Desestructuración en argumentos lambda

Digamos que quieres aceptar un Pair<*,*>en una lambda. Normalmente, manejar esto sería molesto. Como ejemplo, aquí hay una lambda que toma un Pairy comprueba si los dos valores son iguales:

{it.first==it.second}

Esto es largo y torpe. Afortunadamente, Kotlin le permite desestructurar cualquier tipo destruible (cualquier tipo que implemente componentN()métodos, como Pair, Tripleetc.) como argumentos para una lambda. Entonces, podemos reescribir esto de la siguiente manera:

{(a,b)->a==b}

Se parece al patrón que coincide con una tupla en algo así como F #, y lo es en muchos casos. Pero una amplia variedad de tipos en Kotlin admite la desestructuración ( MatchResultes útil).

Sin embargo, puedes tomar más argumentos. Digamos que su lambda tuvo que tomar un Pairvalor adicional. Simplemente escribirías la firma lambda así:

(a,b),c->  // pair first
a,(b,c)->  // pair second
caracol_
fuente