Alcuni piccoli consigli sul code-golf
Questi suggerimenti erano un po 'troppo piccoli per una risposta separata, quindi userò questa risposta per suggerimenti di codegolfing molto piccoli che ho trovato o trovato, e non sono ancora menzionati negli altri suggerimenti:
Rimozione dell'ultimo carattere di una stringa:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
In alcuni casi sai in anticipo quale è l'ultimo carattere e sai anche che questo personaggio compare una sola volta nella stringa. In tal caso puoi .split
invece utilizzare :
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Scorciatoie di codifica:
// 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
Tutte le codifiche hanno un nome canonico utilizzato java.nio
nell'API, nonché un nome canonico utilizzato nelle API java.io
e java.lang
. Ecco un elenco completo di tutte le codifiche supportate in Java. Quindi usa sempre il più corto dei due; il secondo è generalmente più breve (come UTF-8
vs utf8
, Windows-1252
vs Cp1252
, ecc.), ma non sempre ( UTF-16BE
vs UnicodeBigUnmarked
).
Booleano casuale:
// 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:
Esistono molti modi diversi per verificare la presenza di numeri primi o ottenere tutti i numeri primi, ma la risposta di @ SaraJ qui è la più breve. Ecco un copia-incolla come riferimento:
// 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: di solito è possibile unirlo con altri loop esistenti a seconda di come si desidera utilizzarlo, quindi non sarà necessario un metodo separato. Ciò ha consentito di risparmiare molti byte in questa risposta, ad esempio.
Troncamento intero anziché Math.floor / Math.ceil:
Se stai usando doppi / float positivi e li vuoi floor
, non usare Math.floor
ma usa (int)
invece un -cast (poiché Java si tronca su numeri interi):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
Lo stesso trucco può essere applicato ai doppi / float negativi che vuoi ceil
invece:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Usa &1
invece di%2
per sbarazzarsi della parentesi:
Poiché la Precedenza operatore di &
è inferiore agli operatori aritmetici predefiniti come */+-
e %
, in alcuni casi è possibile eliminare la parentesi.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Nota che questo non aiuta davvero nei controlli booleani, perché poi avresti ancora bisogno di parentesi, sono solo spostati un po ':
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers e creazione di variabili per chiamate a metodi statici:
Quando si utilizza BigIntegers, crearlo solo una volta che è possibile riutilizzare. Come forse sapete, BigInteger contiene campi statici per ZERO
, ONE
e TEN
. Quindi quando usi solo quei tre, non hai bisogno di un import
ma puoi usarlo java.Math.BigInteger
direttamente.
// 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: è necessario utilizzare =null
così t
è inizializzato per poter usaret.
.
A volte puoi aggiungere più BigInteger per crearne un altro per salvare byte. Quindi supponiamo che tu voglia avere i BigIntegers 1,10,12
per qualche motivo:
// 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
Come sottolineato correttamente nei commenti, il trucco con le BigInteger t=null;
sue chiamate a metodi statici può essere utilizzato anche con altre classi.
Ad esempio, questa risposta del 2011 può essere giocata a golf:
// 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()
invece di toCharArray()
Quando vuoi passare in rassegna i caratteri di una stringa, di solito esegui questa operazione:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Il ciclo sopra i caratteri può essere utile quando li si stampa o si aggiunge a una stringa o qualcosa di simile.
Tuttavia, se si utilizzano i caratteri solo per alcuni calcoli del numero unicode, è possibile sostituire il char
con int
, E è possibile sostituire toCharArray()
con getBytes()
:
for(int c:s.getBytes()) // 23 bytes
O ancora più breve in Java 8+:
s.chars().forEach(c->...) // 22 bytes
In Java 10+ è ora possibile eseguire il looping del carattere da stampare in 22 byte:
for(var c:s.split("")) // 22 bytes
Articolo casuale da un 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
Controlla se una stringa contiene spazi iniziali / finali
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
Perché questo funziona, quando !=
su Stringhe è necessario verificare il riferimento anziché il valore in Java? Perché String#trim
restituirà " Una copia di questa stringa con lo spazio bianco iniziale e finale rimosso, o questa stringa se non ha spazio bianco iniziale o finale . " L'ho usato, dopo che qualcuno me l'ha suggerito, in questa mia risposta .
Palindrome:
Per verificare se una stringa è un palindromo (tenendo presente sia la lunghezza pari che quella dispari delle stringhe), questa è la più breve ( .contains
funziona qui perché sappiamo che sia la stringa stessa che la sua forma invertita sono di uguale lunghezza):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
invece di .equals(...+"")
ringraziare il commento di @assylias qui .
O è 0 o entrambi sono 0?
Penso che molti lo sappiano già: se vuoi controllare se uno a
o b
è zero, moltiplica invece per salvare byte:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
E se vuoi controllare se entrambi a
e b
sono zero, puoi usare un bit-OR o aggiungerli insieme se sono sempre positivi:
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)
Pari = 1, dispari = -1; o vice versa
// 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
Il motivo per cui aggiungo questo è stato dopo aver visto k+(k%2<1?1:-1)
in questa risposta :
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
Tempi di loop nel programma completo
Se abbiamo una sfida in cui un programma completo è obbligatorio e dobbiamo ripetere un determinato numero di volte, possiamo fare quanto segue:
// 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 stesso vale quando dobbiamo prendere questo intervallo come input:
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
Ringraziamo @JackAmmo in questo commento .
try-finally invece di try-catch (Eccezione e) quando ritorna e quando usarlo
Se non puoi usare un throws Exception
ma catch
devi e fare qualcosa con esso prima di tornare, puoi finally
invece usare :
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Per quanto riguarda un esempio di quando usare un try-catch
, posso fare riferimento a questa mia risposta (il merito del golf indiretto va a @KamilDrakari ). In questa sfida dobbiamo passare in diagonale su una matrice NxM, quindi dobbiamo determinare se la quantità di colonne o la quantità di righe è la più bassa come la massima nel ciclo for (che è piuttosto costoso in termini di byte:) i<Math.min(a.length,a[0].length)
. Quindi, semplicemente catturare l' ArrayIndexOutOfBoundsException
utilizzo catch-finally
è più breve di questo controllo e quindi salva byte:
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: Questo ha funzionato solo a causa di return r;
in the finally. Mi è stato suggerito di modificare la prima cella, come ha fatto @KamilDrakari nella sua risposta C # per salvare byte. Tuttavia, in Java questo significa che dovrò cambiarlo in m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 byte), aumentando effettivamente il conteggio dei byte invece di diminuire se avessi potuto usare finally
.
Math.pow (2, n)
Quando vuoi una potenza di 2, un approccio bit-saggio è molto più breve:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Combinazione di controlli logici e bit bit anziché utilizzare la parentesi
Penso che ormai sia ben noto &
e che |
possa essere usato al posto di &&
e ||
nei controlli logici Java (booleani). In alcuni casi dovresti comunque utilizzare &&
invece di &
prevenire errori, ad esempio index >= 0 && array[index].doSomething
. Se &&
verrà modificato in &
qui, valuterà comunque la parte in cui utilizza l'indice nell'array, causando un ArrayIndexOutOfBoundsException
, quindi l'utilizzo di &&
in questo caso anziché&
.
Finora le basi di &&
/ ||
vs &
/|
in Java.
Quando si desidera verificare (A or B) and C
, il più breve potrebbe sembrare utilizzare gli operatori bit-saggio come questo:
(A|B)&C // 7 bytes
Tuttavia, poiché gli operatori bit-wise hanno la precedenza dell'operatore sui controlli logici, è possibile combinare entrambi per salvare un byte qui:
A|B&&C // 6 bytes
Usa n+=...-n
invece di(long)...
Se hai un long sia in sia in output in lambda, ad esempio quando lo usi Math.pow
, puoi salvare un byte usando n+=...-n
invece di (long)...
.
Per esempio:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Questo salvato un byte in questa risposta di miniera , e anche due byte combinando -n-1
a +~n
in questa risposta di mine .
package
può essere saltato.