Algunos pequeños consejos de golf de código
Estos consejos eran demasiado pequeños para respuestas separadas, por lo que utilizaré esta respuesta para consejos muy pequeños de codegolf que encontré o se me ocurrieron, y que aún no se mencionan en los otros consejos:
Eliminar el último carácter de una cadena:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
En algunos casos, usted sabe de antemano cuál es el último carácter, y también sabe que este carácter solo aparece una vez en la Cadena. En ese caso, puede usar .split
en su lugar:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Atajos de codificación:
// When you want to get the UTF-8 bytes I used to do this:
s.getBytes("UTF-8"); // 20 bytes
// But you can also use "UTF8" for the same result:
s.getBytes("UTF8"); // 19 bytes
Todas las codificaciones tienen un nombre canónico utilizado en la java.nio
API, así como un nombre canónico utilizado en los java.io
y java.lang
las API. Aquí hay una lista completa de todas las codificaciones compatibles en Java. Así que siempre usa el más corto de los dos; el segundo suele ser más corto (como UTF-8
vs utf8
, Windows-1252
vs Cp1252
, etc.), pero no siempre ( UTF-16BE
vs UnicodeBigUnmarked
).
Booleano aleatorio:
// You could do something like this:
new java.util.Random().nextBoolean() // 36 bytes
// But as mentioned before in @Geobits' answer, Math.random() doesn't require an import:
Math.random()<.5 // 16 bytes
Primes:
Hay muchas formas diferentes de verificar los números primos u obtener todos los números primos, pero la respuesta de @ SaraJ aquí es la más corta. Aquí hay una copia-pegar como referencia:
// Check if n is a prime:
n->{int i=1;for(;n%++i%n>0;);return n==i;}
// Which can easily be modified to loop through primes:
v->{for(int n=2,i;;){for(i=1;n%++i%n>0;);if(n++==i)/*do something with prime `i` here*/;}}
NOTA: Por lo general, puede fusionarlo con otros bucles existentes dependiendo de cómo desee usarlo, por lo que no necesitará un método separado. Esto ahorró muchos bytes en esta respuesta, por ejemplo.
Truncamiento de enteros en lugar de Math.floor / Math.ceil:
Si está utilizando dobles / flotantes positivos y desea floor
utilizarlos, no los utilice, Math.floor
sino que use un (int)
-cast en su lugar (ya que Java se trunca en los enteros):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
El mismo truco se puede aplicar a dobles / flotantes negativos que desee ceil
:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Use en &1
lugar de %2
deshacerse del paréntesis:
Debido a que la precedencia de operadores de &
es menor que los operadores aritméticos predeterminados como */+-
y %
, en algunos casos puede deshacerse del paréntesis.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Tenga en cuenta que esto realmente no ayuda en las comprobaciones booleanas, porque aún necesitaría paréntesis, solo se movieron un poco:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers y creando variables para llamadas a métodos estáticos:
Cuando use BigIntegers, créelo solo una vez y luego podrá reutilizarlo. Como ya sabrán, BigInteger contiene campos estáticos para ZERO
, ONE
y TEN
. Entonces, cuando solo usa esos tres, no necesita un import
pero puede usarlo java.Math.BigInteger
directamente.
// So instead of this:
import java.math.BigInteger.*;
BigInteger a=BigInteger.ONE,b=BigInteger.ZERO; // 76 bytes
// or this:
java.math.BigInteger a=java.math.BigInteger.ONE,b=a.ZERO; // 57 bytes
// Use this:
java.math.BigInteger t=null,a=t.ONE,b=t.ZERO; // 45 bytes
NOTA: Usted tiene que usar =null
por lo que t
se inicializa con el fin de utilizar t.
.
A veces puede agregar múltiples BigIntegers para crear otro para guardar bytes. Entonces, digamos que quieres tener BigIntegers 1,10,12
por alguna razón:
// So instead of this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=new BigInteger(12); // 55 bytes
// Use this:
BigInteger t=null,a=t.ONE,b=t.TEN,c=b.add(a).add(a); // 52 bytes
Como se señaló correctamente en los comentarios, el truco con BigInteger t=null;
sus llamadas a métodos estáticos también se puede usar con otras clases.
Por ejemplo, esta respuesta de 2011 se puede jugar:
// 173 bytes:
import java.util.*;class g{public static void main(String[]p){String[]a=p[0].split(""),b=p[1].split("");Arrays.sort(a);Arrays.sort(b);System.out.print(Arrays.equals(a,b));}}
// 163 bytes
class g{public static void main(String[]p){java.util.Arrays x=null;String[]a=p[0].split(""),b=p[1].split("");x.sort(a);x.sort(b);System.out.print(x.equals(a,b));}}
getBytes()
en lugar de toCharArray()
Cuando desee recorrer los caracteres de una Cadena, generalmente hará esto:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Recorrer los caracteres puede ser útil al imprimirlos, agregarlos a una cadena o algo similar.
Sin embargo, si solo usa los caracteres para algunos cálculos de números Unicode, puede reemplazarlos char
con int
Y, y puede reemplazar toCharArray()
con getBytes()
:
for(int c:s.getBytes()) // 23 bytes
O incluso más corto en Java 8+:
s.chars().forEach(c->...) // 22 bytes
En Java 10+, el bucle sobre el carácter a imprimir ahora también se puede hacer en 22 bytes:
for(var c:s.split("")) // 22 bytes
Artículo aleatorio de a List
:
List l=...;
// When we have an `import java.util.*;` in our code, shuffling is shortest:
return l.get(new Random().nextInt(l.size())); // 45 bytes
return l.get((int)(Math.random()*l.size())); // 44 bytes
Collections.shuffle(l);return l.get(0); // 39 bytes
// When we don't have an `import java.util.*` in our code, `Math.random` is shortest:
return l.get(new java.util.Random().nextInt(l.size())); // 55 bytes
return l.get((int)(Math.random()*l.size())); // 44 bytes
java.util.Collections.shuffle(l);return l.get(0); // 49 bytes
Compruebe si una cadena contiene espacios iniciales / finales
String s=...;
// I used to use a regex like this:
s.matches(" .*|.* ") // 20 bytes
// But this is shorter:
!s.trim().equals(s) // 19 bytes
// And this is even shorter due to a nice feature of String#trim:
s!=s.trim() // 11 bytes
¿Por qué funciona esto, cuando !=
en Strings se busca una referencia en lugar de un valor en Java? Porque String#trim
devolverá " Una copia de esta cadena con espacios en blanco iniciales y finales eliminados, o esta cadena si no tiene espacios en blanco iniciales o finales " . Utilicé esto, después de que alguien me sugirió esto, en esta respuesta mía .
Palíndromo:
Para verificar si una Cadena es un palíndromo (teniendo en cuenta las longitudes pares e impares de las Cadenas), esta es la más corta ( .contains
funciona aquí porque sabemos que tanto la Cadena en sí como su forma invertida tienen la misma longitud):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
en lugar de .equals(...+"")
gracias al comentario de @assylias aquí .
¿O es 0 o ambos son 0?
Creo que la mayoría ya conoce esta: si desea comprobar si a
o b
es cero, multiplique en su lugar para guardar bytes:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
Y si desea verificar si ambos a
y b
son cero, puede usar un OR bit a bit o agregarlos juntos si siempre son positivos:
a==0&b==0 // 9 bytes
(a|b)==0 // 8 bytes (if either `a`, `b` or both can be negative)
a+b<1 // 5 bytes (this only works if neither `a` nor `b` can be negative)
Par = 1, impar = -1; o viceversa
// even = 1; odd = -1:
n%2<1?1:-1 // 10 bytes
1-n%2*2 // 7 bytes
// even = -1; odd = 1:
n%2<1?-1:1 // 10 bytes
n%2*2-1 // 7 bytes
La razón por la que agrego esto fue después de ver k+(k%2<1?1:-1)
en esta respuesta :
k+(k%2<1?1:-1) // 14 bytes
// This would already have been shorter:
k%2<1?k+1:k-1 // 13 bytes
// But it can also be:
k%2*-2-~k // 9 bytes
n
Tiempos de bucle en el programa completo
Si tenemos un desafío en el que un programa completo es obligatorio, y necesitamos realizar un ciclo específico de veces, podemos hacer lo siguiente:
// instead of:
interface M{static void main(String[]a){for(int n=50;n-->0;)/*do something*/}} // 78 bytes
// we could do:
interface M{static void main(String[]a){for(M m:new M[50])/*do something*/}} // 76 bytes
Lo mismo se aplica cuando tenemos que tomar este rango como entrada:
interface M{static void main(String[]a){for(int n=new Byte(a[0]);n-->0;)/*do something*/}} // 90 bytes
interface M{static void main(String[]a){for(M m:new M[new Byte(a[0])])/*do something*/}} // 88 bytes
Gracias a @JackAmmo en este comentario .
try-finally en lugar de try-catch (Excepción e) al regresar y cuándo usarlo
Si no puede usar un throws Exception
pero tiene que catch
hacerlo y hacer algo con él antes de regresar, puede usar finally
en su lugar:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
En cuanto a un ejemplo de cuándo usar un try-catch
, puedo referirme a esta respuesta mía (el crédito por el golf indirecto va a @KamilDrakari ). En este desafío, debemos realizar un bucle en diagonal sobre una matriz NxM, por lo que debemos determinar si la cantidad de columnas o la cantidad de filas es la más baja como nuestro máximo en el bucle for (que es bastante costoso en términos de bytes i<Math.min(a.length,a[0].length)
). Por lo tanto, simplemente capturar el ArrayIndexOutOfBoundsException
uso catch-finally
es más corto que esta verificación y, por lo tanto, ahorra bytes:
int[] a = ...;
int r=0,i=0;for(;i<Math.min(a.length,a[0].length);)r=...i++...;return r; // 66 bytes
int r=0,i=0;try{for(;;)r=...i++...;}finally{return r;} // 48 bytes
NOTA: Esto solo funcionó debido return r;
al final. Me han sugerido que modifique la primera celda, como @KamilDrakari hizo en su respuesta de C # para guardar bytes. Sin embargo, en Java esto significa que tendré que cambiarlo a m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 bytes), en realidad aumentando el recuento de bytes en lugar de disminuir si pudiera haberlo usado finally
.
Math.pow (2, n)
Cuando quieres una potencia de 2, un enfoque basado en bits es mucho más corto:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Combinando controles lógicos y de bits en lugar de usar paréntesis
Creo que ahora es bien conocido eso &
y |
puede usarse en lugar de &&
y ||
en las comprobaciones lógicas Java (booleanas). Sin embargo, en algunos casos aún querrás usar en &&
lugar de &
evitar errores, como index >= 0 && array[index].doSomething
. Si &&
se cambiara a &
aquí, todavía evaluará la parte donde usa el índice en la matriz, causando un ArrayIndexOutOfBoundsException
, de ahí el uso de &&
en este caso en lugar de &
.
Hasta ahora, los conceptos básicos de &&
/ ||
vs &
/ |
en Java.
Cuando desee verificar (A or B) and C
, el más corto puede parecer usar los operadores de bits como este:
(A|B)&C // 7 bytes
Sin embargo, debido a que los operadores de bits tienen prioridad de operador sobre las comprobaciones lógicas, puede combinar ambos para guardar un byte aquí:
A|B&&C // 6 bytes
Usar en n+=...-n
lugar de(long)...
Cuando tiene un largo como entrada y salida en un lambda, por ejemplo, cuando lo usa Math.pow
, puede guardar un byte usando en n+=...-n
lugar de (long)...
.
Por ejemplo:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Esto ahorró un byte en esta respuesta mía , e incluso dos bytes mediante la combinación de -n-1
a +~n
en esta respuesta mía .
package
Se puede omitir.