Деякі невеликі поради щодо гольфу з кодом
Ці поради були трохи замалі для розділених відповідей, тому я буду використовувати цю відповідь для дуже маленьких порад щодо кодового гольфу, які я знайшов або придумав, і в інших порадах поки не згадується:
Видалення останнього символу рядка:
// I used to do something like this:
s.substring(0,s.length()-1) // 27 bytes
// But this is shorter:
s.replaceAll(".$","") // 21 bytes
У деяких випадках ви заздалегідь знаєте, що є останнім символом, а також знаєте, що цей символ виникає лише один раз у рядку. У такому випадку ви можете використовувати .split
замість цього:
// As example: "100%" to "100"
s.split("%")[0] // 15 bytes
Кодування ярликів:
// 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
Усі кодування мають канонічну назву, що використовується в java.nio
API, а також канонічне ім'я, що використовується в API java.io
та java.lang
API. Ось повний список усіх підтримуваних кодувань на Java. Тому завжди використовуйте найкоротший з двох; другий зазвичай коротший (як UTF-8
vs utf8
, Windows-1252
vs Cp1252
тощо), але не завжди ( UTF-16BE
vs UnicodeBigUnmarked
).
Випадкові булі:
// 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
Примери:
Існує дуже багато різних способів перевірити чистість чи отримати всі пролі , але відповідь @ SaraJ тут найкоротша. Ось копія-вставка як довідка:
// 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*/;}}
ПРИМІТКА: Зазвичай ви можете об'єднати його з іншими існуючими циклами залежно від способу його використання, тому вам не знадобиться окремий метод. Наприклад, це врятувало багато байтів у цій відповіді .
Урізання цілого числа замість Math.floor / Math.ceil:
Якщо ви використовуєте додатні подвійні / поплавці, і ви хочете floor
їх, не використовуйте, Math.floor
а використовуйте (int)
-cast замість цього (оскільки Java скорочує цілі числа):
double d = 54.99;
int n=(int)Math.floor(d); // 25 bytes
int m=(int)d; // 13 bytes
// Outputs 54 for both
Цей же трюк можна застосувати до негативних парних чи поплавців, які ви хочете ceil
замість цього:
double d = -54.99;
int n=(int)Math.ceil(d); // 24 bytes
int m=(int)d; // 13 bytes
// Outputs -54 for both
Використовуйте &1
замість%2
щоб позбутися дужок:
Оскільки оператор Позачерговий з &
нижче арифметичних операторів по замовчуванням , як */+-
і %
ви можете позбутися від дужок в деяких випадках.
// So instead of this:
(i+j)%2 // 7 bytes
// Use this:
i+j&1 // 5 bytes
Зауважте, що це не дуже допомагає в булевих перевірях, оскільки тоді вам все одно знадобляться круглі дужки, вони просто трохи переміщаються:
(i+j)%2<1 // 9 bytes
(i+j&1)<1 // 9 bytes
BigIntegers та створення змінних для статичних викликів методу:
Використовуючи BigIntegers, створіть його лише один раз, який потім зможете повторно використовувати. Як ви знаєте, BigInteger містить статичні поля для ZERO
, ONE
і TEN
. Тож, коли ви використовуєте лише ці три, вам не потрібно, import
але можна використовувати java.Math.BigInteger
безпосередньо.
// 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
ПРИМІТКА. Для використання вам потрібно ініціалізувати =null
так .t
t.
Іноді ви можете додати кілька BigIntegers, щоб створити інший для збереження байтів. Тож скажімо, ви хочете 1,10,12
чомусь мати BigIntegers :
// 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
Як правильно зазначено в коментарях, трюк із BigInteger t=null;
статичними викликами методу може бути використаний і для інших класів.
Наприклад, ця відповідь з 2011 року може бути гольф:
// 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()
замість toCharArray()
Коли ви хочете перевести цикл на символів рядка, зазвичай це зробите:
for(char c:s.toCharArray()) // 27 bytes
// or this:
for(String c:s.split("")) // 25 bytes
Перекидання символів може бути корисним під час друку або додавання їх до рядка або чогось подібного.
Однак, якщо ви використовуєте тільки символи для деяких розрахунків юнікода-номер, ви можете замінити char
з int
, і ви можете замінити toCharArray()
з getBytes()
:
for(int c:s.getBytes()) // 23 bytes
Або навіть коротше в Java 8+:
s.chars().forEach(c->...) // 22 bytes
У Java 10+ перегляд символу для друку також можна виконати в 22 байтах:
for(var c:s.split("")) // 22 bytes
Випадковий елемент із 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
Перевірте, чи містить рядок провідні / кінцеві пробіли
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
Чому це працює, коли !=
на Strings слід перевіряти посилання замість значення на Java? Тому що String#trim
повернеться « Копія цього рядка з передньої і задньої прогалини видаляються, або це рядок , якщо вона не має передньої або задньої білого простору . » Я використав це, після того, як хто - то запропонував мені це, в цьому моя відповідь .
Паліндром:
Щоб перевірити, чи струна є паліндром (маючи на увазі і парні, і непарні довжини струн), це найкоротше ( .contains
працює тут, тому що ми знаємо, що і сама струна, і її зворотна форма мають однакову довжину):
String s=...;
s.contains(new StringBuffer(s).reverse()) // 41 bytes
.contains(...)
замість .equals(...+"")
подяки коментаря @assylias тут .
Або 0, або обидва - 0?
Я думаю, що більшість з них уже знає це: якщо ви хочете перевірити, чи один a
чи b
нуль, помножте натомість, щоб зберегти байти:
a==0|b==0 // 9 bytes
a*b==0 // 6 bytes
І якщо ви хочете перевірити, чи обоє, a
і b
нулі, ви можете використовувати побітові АБО або додати їх разом, якщо вони завжди позитивні:
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)
Четний = 1, непарний = -1; або навпаки
// 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
Причину цього я додав, побачивши k+(k%2<1?1:-1)
в цій відповіді :
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
Часи в Повній програмі
Якщо у нас є виклик, коли повноцінна програма є обов'язковою, і нам потрібно циклічно фіксувати певну кількість разів, ми можемо зробити наступне:
// 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
Це ж стосується, коли ми повинні сприймати цей діапазон як вхідний:
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
Кредит @JackAmmo в цьому коментарі .
try-нарешті замість try-catch (Виняток e) при поверненні та коли його використовувати
Якщо ви не можете використовувати, throws Exception
але потрібно catch
щось робити з цим перед поверненням, ви можете скористатися ним finally
:
try{...}catch(Exception e){return ...;} // 33 bytes
try{...}finally{return ...;} // 22 bytes
Що стосується прикладу, коли потрібно використовувати try-catch
, я можу посилатися на цю свою відповідь (кредит на непрямий гольф йде на @KamilDrakari ). У цьому виклику нам потрібно провести діагональне перетворення за матрицею NxM, тому ми маємо визначити, чи кількість стовпців чи кількість рядків є найнижчою як наш максимум у фор-циклі (що досить багата з точки зору байтів:) i<Math.min(a.length,a[0].length)
. Отже, просто перехопити ArrayIndexOutOfBoundsException
використання catch-finally
коротше, ніж ця перевірка, і, таким чином, економиться байт:
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
ПРИМІТКА: Це спрацювало лише через, return r;
нарешті. Мені запропонували змінити першу клітинку, як @KamilDrakari зробив у своїй відповіді C #, щоб зберегти байти. Однак у Java це означає, що мені доведеться змінити його на m->{try{for(int i=1;;m[0][0]=f(m[0][0],m[i][i++]));}catch(Exception e){}}
(73 байти), фактично збільшуючи кількість байтів, а не зменшуючи, якщо я міг би використовуватиfinally
.
Math.pow (2, n)
Коли вам потрібно потужність 2, трохи розумніший підхід значно коротший:
(int)Math.pow(2,n) // 16 bytes
(1<<n) // 6 bytes
Поєднання бітових та логічних перевірок замість використання дужок
Я думаю , що це добре відомо тепер , що &
і |
може бути використаний замість &&
і ||
в Java (логічне) логічних перевірок. У деяких випадках ви все одно хочете використовувати &&
замість того, &
щоб запобігти помилкам, хоча index >= 0 && array[index].doSomething
. Якщо тут &&
буде змінено значення &
, воно все одно буде оцінювати частину, де він використовує індекс у масиві, викликаючи ArrayIndexOutOfBoundsException
, отже, використання &&
у цьому випадку замість&
.
Поки основи &&
/ ||
vs &
/|
на Java.
Коли ви хочете перевірити (A or B) and C
, може здатися, що найкоротші можуть використовувати такі розрядні оператори:
(A|B)&C // 7 bytes
Однак, оскільки бітові оператори мають перевагу оператора над логічними перевірками, ви можете комбінувати обидва, щоб зберегти байт тут:
A|B&&C // 6 bytes
Використовуйте n+=...-n
замість(long)...
Якщо у лямбда у вас є довгий і вихідний, і, наприклад, при використанні Math.pow
, ви можете зберегти байт, використовуючи n+=...-n
замість (long)...
.
Наприклад:
n->(long)Math.pow(10,n) // 23 bytes
n->n+=Math.pow(10,n)-n // 22 bytes
Це врятувало байти в цій відповіді шахти , і навіть два байта, комбінуючи -n-1
в +~n
в цій відповіді шахти .
package
можна пропустити.