Quelques petits conseils de code-golf
Ces astuces étaient un peu trop petites pour une réponse séparée, je vais donc utiliser cette réponse pour de très petites astuces de golf-code que j'ai trouvées ou proposées, et qui ne sont pas encore mentionnées dans les autres astuces:
Supprimer le dernier caractère d'une chaîne:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
Dans certains cas, vous savez à l’avance le dernier caractère et vous savez également que ce caractère n’apparaît qu’une fois dans la chaîne. Dans ce cas, vous pouvez utiliser à la .split
place:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Raccourcis d'encodage:
// 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
Tous les encodages ont un nom canonique utilisé dans l' java.nio
API, ainsi qu'un nom canonique utilisé dans les API java.io
et java.lang
. Voici une liste complète de tous les encodages pris en charge en Java. Donc, utilisez toujours le plus court des deux; la seconde est généralement plus courte (comme UTF-8
vs utf8
, Windows-1252
vs Cp1252
, etc.), mais pas toujours ( UTF-16BE
vs UnicodeBigUnmarked
).
Booléen aléatoire:
// 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:
Il existe différentes façons de rechercher des nombres premiers ou d'obtenir tous les nombres premiers, mais la réponse de @ SaraJ est la plus courte. Voici un copier-coller comme référence:
// 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*/;}}
REMARQUE: En règle générale, vous pouvez le fusionner avec d'autres boucles existantes en fonction de la manière dont vous souhaitez l'utiliser. Vous n'avez donc pas besoin d'une méthode distincte. Cela a permis d'économiser beaucoup d'octets dans cette réponse, par exemple.
Troncature d'entier au lieu de Math.floor / Math.ceil:
Si vous utilisez des doubles / floats positifs et que vous souhaitez floor
les utiliser, n'utilisez pas, Math.floor
mais utilisez (int)
plutôt -cast (car Java tronque les entiers):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
La même astuce peut être appliquée aux doublons / flotteurs négatifs que vous souhaitez utiliser à la ceil
place:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Utilisez &1
au lieu de %2
pour vous débarrasser des parenthèses:
Étant donné que la priorité de l' opérateur&
est inférieure à celle des opérateurs arithmétiques par défaut tels que */+-
et %
, vous pouvez supprimer les parenthèses dans certains cas.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Notez que cela n'aide pas vraiment dans les contrôles booléens, car alors vous auriez toujours besoin de parenthèses, elles sont juste déplacées un peu:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers et la création de variables pour les appels de méthodes statiques:
Lorsque vous utilisez BigIntegers, créez-le une seule fois, que vous pourrez ensuite réutiliser. Comme vous le savez peut-être, BigInteger contient des champs statiques pour ZERO
, ONE
et TEN
. Ainsi, lorsque vous utilisez uniquement ces trois éléments, vous n’avez pas besoin d’un, import
mais vous pouvez les utiliser java.Math.BigInteger
directement.
// 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
NOTE: Vous devez utiliser =null
ainsi t
est initialisé pour pouvoir utiliser t.
.
Parfois, vous pouvez ajouter plusieurs BigIntegers pour en créer un autre afin de sauvegarder des octets. Alors disons que vous voulez avoir les BigIntegers 1,10,12
pour une raison quelconque:
// 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
Comme correctement souligné dans les commentaires, l'astuce avec BigInteger t=null;
ses appels de méthode statique peut également être utilisée avec d'autres classes.
Par exemple, cette réponse de 2011 peut être lue:
// 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()
au lieu de toCharArray()
Lorsque vous souhaitez effectuer une boucle sur les caractères d'une chaîne, procédez comme suit:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Faire une boucle sur les caractères peut être utile pour les imprimer, les ajouter à une chaîne ou quelque chose de similaire.
Toutefois, si vous utilisez uniquement les caractères pour certains calculs de nombre unicode, vous pouvez remplacer le char
avec int
, ET vous pouvez le remplacer toCharArray()
par getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Ou même plus court en Java 8+:
s.chars().forEach(c->...) // 22 bytes
En Java 10+, le bouclage sur le caractère à imprimer peut maintenant aussi être effectué sur 22 octets:
for(var c:s.split("")) // 22 bytes
Article aléatoire 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
Vérifier si une chaîne contient des espaces de début / fin
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
Pourquoi cela fonctionne-t-il, alors que !=
sur Strings, il faut vérifier la référence au lieu de la valeur en Java? Car String#trim
retournera " Une copie de cette chaîne avec les espaces blancs de début et de fin supprimés, ou cette chaîne si elle n'a pas d'espace blanc de début ou de fin . " Je l'ai utilisé, après que quelqu'un me l'ait suggéré, dans ma réponse .
Palindrome:
Pour vérifier si une chaîne est un palindrome (en gardant à l'esprit les longueurs paires et impaires des chaînes), il s'agit de la plus courte ( .contains
fonctionne ici car nous savons que la chaîne elle-même et sa forme inversée sont de même longueur):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
au lieu de .equals(...+"")
grâce au commentaire de @assylias ici .
Soit 0, ou les deux sont 0?
Je pense que la plupart connaissent déjà celui-ci: si vous voulez vérifier si l'un a
ou l' autre b
est égal à zéro, multipliez-le pour sauvegarder les octets:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
Et si vous voulez vérifier si les deux a
et b
sont égaux à zéro, vous pouvez utiliser un opérateur OR, ou les ajouter ensemble si elles sont toujours positives:
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)
Pair = 1, impair = -1; ou 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
La raison pour laquelle j'ai ajouté ceci était après avoir vu k+(k%2<1?1:-1)
dans cette réponse :
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
Temps de boucle dans le programme complet
Si nous avons un défi pour lequel un programme complet est obligatoire et que nous devons boucler un nombre de fois spécifique, nous pouvons procéder comme suit:
// 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
Il en va de même lorsque nous devons prendre cette plage en entrée:
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
Merci à @JackAmmo pour ce commentaire .
try-finally au lieu de try-catch (Exception e) lors du retour et quand l'utiliser
Si vous ne pouvez pas utiliser un throws Exception
mais devez le faire catch
et y faire quelque chose avant de revenir, vous pouvez utiliser à la finally
place:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
En ce qui concerne un exemple d'utilisation d'un try-catch
, je peux me référer à cette réponse (le crédit pour le golf indirect va à @KamilDrakari ). Dans ce défi, nous devons boucler en diagonale sur une matrice NxM, nous devons donc déterminer si le nombre de colonnes ou le nombre de lignes est le plus bas que notre maximum dans la boucle for (ce qui est assez coûteux en termes d'octets:) i<Math.min(a.length,a[0].length)
. Donc, attraper simplement l' ArrayIndexOutOfBoundsException
utilisation catch-finally
est plus court que cette vérification, et sauve ainsi des octets:
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
NOTE: Cela a seulement fonctionné à cause de return r;
l'enfin. On m'a suggéré de modifier la première cellule, comme l'a fait @KamilDrakari dans sa réponse en C # pour économiser des octets. Cependant, en Java, cela signifie que je devrai le modifier en m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 octets), ce qui augmenterait le nombre d'octets au lieu de diminuer si j'avais pu l'utiliser finally
.
Math.pow (2, n)
Lorsque vous voulez une puissance de 2, une approche un peu sage est beaucoup plus courte:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Combinaison de contrôles binaires et logiques au lieu d'utiliser des parenthèses
Je pense qu'il est bien connu maintenant que &
et |
peut être utilisé à la place &&
et ||
en Java (Boolean) Les contrôles logiques. Dans certains cas, vous souhaiterez quand même utiliser &&
au lieu de &
pour éviter les erreurs, comme index >= 0 && array[index].doSomething
. Si le &&
serait changé à &
ici, il évaluera toujours la partie où il utilise l'index dans le tableau, provoquant une ArrayIndexOutOfBoundsException
, d'où l'utilisation de &&
dans ce cas à la place de &
.
Jusqu'ici, les bases de &&
/ ||
vs &
/ |
en Java.
Lorsque vous voulez vérifier (A or B) and C
, le plus court peut sembler utiliser les opérateurs binaires comme celui-ci:
(A|B)&C // 7 bytes
Toutefois, comme les opérateurs au niveau des bits ont priorité sur les contrôles logiques, vous pouvez combiner les deux pour enregistrer un octet ici:
A|B&&C // 6 bytes
Utiliser n+=...-n
au lieu de(long)...
Lorsque vous avez un long comme dans et sortie dans un lambda, par exemple lors de l'utilisation Math.pow
, vous pouvez enregistrer un octet en utilisant à la n+=...-n
place de (long)...
.
Par exemple:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Cela a sauvé un octet dans cette réponse à moi , et même deux octets en combinant -n-1
à +~n
dans cette réponse à moi .
package
peut être sauté.