Typowa implementacja FizzBuzz , którą widziałem, używa czeku% 15 dla drukowanie „FizzBuzz”
Czy mógłbyś dać mi znać, jeśli jest coś złego / lepszego w tym podejściu?
public class FizzBuzz { public static void main(String[] args) { for (int i = 1; i <= 100; i++) { boolean fizzOrBuzz = false; if (i % 3 == 0) { System.out.print("Fizz"); fizzOrBuzz = true; } if (i % 5 == 0) { System.out.print("Buzz"); fizzOrBuzz = true; } if (fizzOrBuzz) { System.out.println(); } else { System.out.println(String.valueOf(i)); } } } }
Komentarze
- Twoja wersja jest zoptymalizowana dla komputera. Wersja Winstona ' jest zoptymalizowana dla ludzi. Muszę zaufać kompilatorowi, że może wykonać dobrą robotę przy ponownym tasowaniu i optymalizacji kodu. Możliwe jest również, że pojedyncza instrukcja io będzie działać szybciej niż dwie oddzielne. Powinieneś ścigać się swoją wersją z drugą.
- Ja ' powiem ci, dlaczego podoba mi się moja wersja (tylko w kontekście wywiadu) 1) łatwość utrzymania – możesz uzewnętrznić Fizz i Buzz jako ciągi znaków, nie ' nie musisz eksternalizować FizzBuzz 2) DRY, użytkownik piszący powyższy kod myśli w kategoriach nie powtarzania się, co lubię
- +1 ale użyj StringBuilder , a nie 100 * System.out.println (..) i Integer.valueOf (i)
- @ cl-r dzięki, zachowam oryginał, aby komentarze nadal miały sens, dzięki za opinię.
- FizzBuzzEnterpriseEdition to najlepsza implementacja, jaka jest: github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition ; D
Odpowiedź
Porównajmy twoją wersję z wersją % 15
:
public class FizzBuzz { public static void main(String[] args) { for (int i = 1; i <= 100; i++) { if (i % 15 == 0) { System.out.println("FizzBuzz") } else if (i % 3 == 0) { System.out.println("Fizz"); } else if (i % 5 == 0) { System.out.println("Buzz"); } else { System.out.println(String.valueOf(i)); } } } }
% 15
wersja to sim Pler i łatwiejszy do odczytania. Ta wersja starannie przedstawia problem w 4 różnych przypadkach i obsługuje każdy z nich. W przeciwieństwie do tego, twoja wersja wprowadza flagę logiki boolowskiej (którą uważam za znaczący anty-wzorzec) i nie do końca intuicyjną zależność od kolejności instrukcji if.
Komentarze
- 15 to ” magiczna liczba ” tutaj. ' d Sugeruję użycie zamiast tego
(3 * 5)
. Kompilator powinien przekonwertować go na 15 … - @Ron – tak jest,
"FizzBuzz"
, według tych kryteriów. Nie żebyś ' był źle koniecznie, ale dla tego typu ' ciekawostki ', konieczność zadeklarowania wszystkiego jest zwykle nieco złagodzona. Na przykład, mówiąc ściśle, w przypadku kodu na poziomie produkcyjnym wszystkie liczby i ciągi, do których się tu odwołuje / wydrukowane, powinny zostać przechwycone jako nazwane stałe. - @ X-Zero, czy mógłbyś przechwycić 3 jako stała, jak byś to nazwał?
- @Winston – Ogólny problem z tym jest taki, że ' jest w zasadzie ' wymyślony ' przykład, więc może być trudno znaleźć dla tego dobre nazwy. Zwłaszcza, że test zasadniczo składa się z ' wielokrotnych ' kontroli – kontynuacja dekompozycji prawdopodobnie doprowadzi do powstania jakiejś struktury tablicy / tabeli (tak … wiem … zmierzam do architektury kosmosu). Więc może
MATCH
?CONDITION
? Urgh. Dlatego w tego rodzaju testach tego rodzaju konwencje są łagodniejsze; test dotyczy podstawowych umiejętności kodowania, a niekoniecznie pełnej abstrakcji. - Poruszyłbym się do środka jeśli-na-15, jeśli możesz ' t dzielić liczbę przez 3, z pewnością ' t dzielić przez 15, oszczędzając 4/5 czeków dla wszystkich liczb
Odpowiedź
Wygląda dobrze. String.valueOf()
jest niepotrzebne, System.out.println(i)
wydrukowałby to samo, ale nadal jest OK. Ten test służy tylko do upewnienia się, że ankietowany może napisać kod zgodnie z treścią strony, do której prowadzi link:
Tego rodzaju pytanie nie pozwoli zidentyfikować świetnych programistów, ale zidentyfikuje słabych. To zdecydowanie krok we właściwym kierunku.
Odpowiedź
Oni z pewnością nie są doskonałe, ale próbowałem kilku sposobów zoptymalizować test, oto wynik (miałem liczby, aby śledzić dobre odpowiedzi) i używam StringBuilder, aby uniknąć inicjalizacji wyjścia IO:
package exercices; import java.util.Hashtable; import org.memneuroo.outils.communs.utilitaires.EnvPrm; public class FizzBuzz { // time for cum with nbIter=30 > 300; 30 ~= 3000 static final int nbIter = 30; static final String sep = "_"; static long ifNested() { final StringBuilder sb = new StringBuilder(); final long t = System.nanoTime(); for (int i = 0; i < nbIter; i++) { sb.append(// i % 15 == 0 // ? "FizzBuzz" // : (i % 3 == 0 // ? "Fizz"// : (i % 5 == 0// ? "Buzz" // : i)));// sb.append(sep); } final long totT = System.nanoTime() - t; System.out.format("ifNested\t%20d\n", totT); // sb.append(EnvPrm.NEWLINE); System.out.println(sb.toString()); return totT; } static long stringPlus() { final StringBuilder sb = new StringBuilder(); final long t = System.nanoTime(); for (int i = 0; i < nbIter; i++) { String x = ""; x += (i % 3 == 0) ? "Fizz" : ""; x += (i % 5 == 0) ? "Buzz" : ""; if (x.isEmpty()) { // MODIF x += Integer.toString(i); } sb.append(x);// sb.append(sep); } final long totT = System.nanoTime() - t; System.out.format("stringPlus\t%20d\n", totT); // sb.append(EnvPrm.NEWLINE); System.out.println(sb.toString()); return totT; } static long withIf() { final StringBuilder sb = new StringBuilder(); final long t = System.nanoTime(); for (int i = 0; i < nbIter; i++) { if (i % 3 == 0) { sb.append("Fizz"); if (i % 5 == 0) { sb.append("Buzz"); } } else if (i % 5 == 0) { sb.append("Buzz"); } else { sb.append(i); }// sb.append(sep); } final long totT = System.nanoTime() - t; System.out.format("withIf\t\t%20d\n", totT); // sb.append(EnvPrm.NEWLINE);System.out.println(sb.toString()); return totT; } static long withArray() { final String[] lis = {"FizzBuzz", "", "", "Fizz", "", "Buzz", "Fizz", "", "", "Fizz", "Buzz", "", "Fizz", "", "",}; final StringBuilder sb = new StringBuilder(); final long t = System.nanoTime(); for (int i = 0; i < nbIter; i++) { final String pos = lis[i % 15]; sb.append(((0 == pos.length()) ? i : pos));// sb.append(sep); } final long totT = System.nanoTime() - t; System.out.format("withArray\t%20d\n", totT); // sb.append(EnvPrm.NEWLINE); System.out.println(sb.toString()); return totT; } static long withTable() { final Hashtable<Integer, String> ht = new Hashtable<>(8); ht.put(0, "FizzBuzz"); ht.put(3, "Fizz"); ht.put(5, "Buzz"); ht.put(6, "Fizz"); ht.put(9, "Fizz"); ht.put(10, "Buzz"); ht.put(12, "Buzz"); final StringBuilder sb = new StringBuilder(); final long t = System.nanoTime(); for (int i = 0; i < nbIter; i++) { final String s = ht.get(i % 15); // MODIF // http://www.developpez.net/forums/d1196563-2/java/general-java/if-null-object-if-objet-null/#post6561766 // sb.append((null == s ? i : s));// sb.append(sep); if (null == s) { sb.append(i); } else { sb.append(s); } } final long totT = System.nanoTime() - t; System.out.format("withTable\t%20d\n", totT); // sb.append(EnvPrm.NEWLINE); System.out.println(sb.toString()); return totT; } static int recursive(final StringBuilder sb, final int n) { if (0 == n) { return 1; } if (n % 3 == 0) { sb.insert(0, "Fizz"); if (n % 5 == 0) { sb.insert(0, "Buzz"); } } else if (n % 5 == 0) { sb.insert(0, "Buzz"); } else { sb.insert(0, n); } return n + recursive(sb, n - 1); } static long recursive() { final StringBuilder sb = new StringBuilder(""); final long t = System.nanoTime(); recursive(sb, nbIter); final long totT = System.nanoTime() - t; System.out.format("recursive\t%20d\n", totT); sb.append(EnvPrm.NEWLINE); System.out.println(sb.toString()); return totT; } /*** @param args */ public static void main(final String[] args) { long cum = 0L, cum2 = 0L; for (int i = 0; i < 5; i++) { System.out.println("------ " + i + " -----"); final long totSb = stringPlus(); final long totIn = ifNested(); final long totWi = withIf(); final long totWa = withArray(); final long totWt = withTable(); final long totRe = recursive(); System.out.format("... stringPlus/withIf :%5d\n", (totSb * 100) / totWi); System.out.format("... ifNested/withIf :%5d\n", (totIn * 100) / totWi); System.out.format("... withArray/withIf :%5d\n", (totWa * 100) / totWi); System.out.format("... withTable/withIf :%5d\n", (totWt * 100) / totWi); System.out.format("... recursive/withIf :%5d\n", (totRe * 100) / totWi); cum += totIn + totSb + totWi + totWa + totWt + totRe; System.out.println("CUMUL (SECOND) == " + cum / 100000000 + "." + cum % 100000000 + "\t , diff: " + (cum - cum2)); cum2 = cum; } } }
Oraz wynik:
------ 0 ----- stringPlus 529397 ifNested 643657 withIf 27657 withArray 43581 withTable 40788 recursive 87441 12Fizz4BuzzFizz78FizzBuzz11Fizz1314BuzzFizz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829BuzzFizz ... stringPlus/withIf : 1914 ... ifNested/withIf : 2327 ... withArray/withIf : 157 ... withTable/withIf : 147 ... recursive/withIf : 316 CUMUL (SECOND) == 0.1372521 , diff: 1372521 ------ 1 ----- stringPlus 345295 ifNested 88280 withIf 88279 withArray 88838 withTable 101689 recursive 93308 12Fizz4BuzzFizz78FizzBuzz11Fizz1314BuzzFizz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829BuzzFizz ... stringPlus/withIf : 391 ... ifNested/withIf : 100 ... withArray/withIf : 100 ... withTable/withIf : 115 ... recursive/withIf : 105 CUMUL (SECOND) == 0.2178210 , diff: 805689 ------ 2 ----- stringPlus 380216 ifNested 36597 withIf 20953 withArray 60063 withTable 91352 recursive 111467 12Fizz4BuzzFizz78FizzBuzz11Fizz1314BuzzFizz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829BuzzFizz ... stringPlus/withIf : 1814 ... ifNested/withIf : 174 ... withArray/withIf : 286 ... withTable/withIf : 435 ... recursive/withIf : 531 CUMUL (SECOND) == 0.2878858 , diff: 700648 ------ 3 ----- stringPlus 489168 ifNested 29613 withIf 22070 withArray 27099 withTable 27378 recursive 91911 12Fizz4BuzzFizz78FizzBuzz11Fizz1314BuzzFizz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829BuzzFizz ... stringPlus/withIf : 2216 ... ifNested/withIf : 134 ... withArray/withIf : 122 ... withTable/withIf : 124 ... recursive/withIf : 416 CUMUL (SECOND) == 0.3566097 , diff: 687239 ------ 4 ----- stringPlus 143035 ifNested 24025 withIf 15924 withArray 23187 withTable 26819 recursive 87162 12Fizz4BuzzFizz78FizzBuzz11Fizz1314BuzzFizz1617Fizz19BuzzFizz2223FizzBuzz26Fizz2829BuzzFizz ... stringPlus/withIf : 898 ... ifNested/withIf : 150 ... withArray/withIf : 145 ... withTable/withIf : 168 ... recursive/withIf : 547 CUMUL (SECOND) == 0.3886249 , diff: 320152
Komentarze
- StringBuilder jest oparty na
char[16]
. Powinieneś ustawić początkową pojemność na wartość większą niż String, który chcesz utworzyć – lub pogorszyć wydajność, ponieważ StringBuilder musi się rozwijać (przydziel nowechar[]
, skopiuj stare dane). Powinieneś także wiedzieć, jak [System.nanoTime()
] (stas-blogspot.blogspot.com /2012/02/what-is-behind-systemnanotime.html) działa i występują problemy.I ' radzę ci wykonać dużo więcej iteracji. Myślę, że teraz głównie mierzysz czas dlaSystem.out.println()
, inne operacje zajmują prawdopodobnie bardzo mało czasu w porównaniu z wywołaniem systemowym. - Powiedz mi, czy kiedykolwiek słyszałem o koncepcji nadmiernej inżynierii …?
- @Max Tak, ale czy ta strona jest przeznaczona do badań, czy nie? Czy dla wygodnych oczu, czy też próba zrozumienia, jak niektóre sposoby są lepsze? Możesz więc wybrać i porównać szybszy, łatwiejszy do odczytania lub sprawdzić kod, aby znaleźć brakującą optymalizację.
- Zobacz Reguły optymalizacji . IMHO Winston Ewert podał najlepszą odpowiedź.
- wyjaśnij matematykę w kodzie tabeli?
Odpowiedź
Oto „wersja, która” jest (IMHO) trochę lepsza dla ludzi niż twoja i lepsza także dla komputerów:
public class FizzBuzz { public static void main(String[] args) { for (int i = 1; i <= 100; i++) { String value; switch (i % 15) { case 3: case 6: case 9: case 12: // divisible by 3, print Fizz value = "Fizz"; break; case 5: case 10: // divisible by 5, print Buzz value = "Buzz"; break; case 0: // divisible by 3 and by 5, print FizzBuzz value = "FizzBuzz"; break; default: // else print the number value = Integer.toString(i); } System.out.println(value); } } }
Komentarze dostarczają informacji do ludzi (ale nadal mogliby to zobaczyć na własną rękę) i jest tylko jedno System.out.println
połączenie na i
.
EDYCJA: To kolejny sposób na buczenie (fokus: DRY):
public class FizzBuzz { public static void main(String[] args) { final String EMPTY = ""; for (int i = 1; i <= 100; i++) { String value = EMPTY; if (i % 3 == 0) value += "Fizz"; if (i % 5 == 0) value += "Buzz"; if (value == EMPTY) value += i; System.out.println(value); } } }
EDYCJA 2: jeszcze inny, używając StringBuilder
, również DRY:
public class FizzBuzz { public static void main(String[] args) { StringBuilder builder = new StringBuilder(1000); for (int i = 1; i <= 100; i++) { final int length = builder.length(); if (i % 3 == 0) builder.append("Fizz"); if (i % 5 == 0) builder.append("Buzz"); if (length == builder.length()) builder.append(i); builder.append("\n"); } System.out.println(builder); } }
Komentarze
- StringBuilder wydaje się szybszym podejściem niż + = w tym przypadku
- @EranMedan – Czy jesteś tego pewien?
StringBuilder
jest dobre, ponieważN
dodaje nie
nie prowadzi doN
przydziałów, jednak tutajN
wynosi co najwyżej 2, co jest wystarczająco mała, że prawdopodobnie wygra ' i nie zrobi różnicy, a ' prawdopodobnie wyniesie 1, co oznacza brak różnicy w wszystko (a może gorzej, ponieważStringBuilder
prawdopodobnie ma dodatkową alokację dla tego 1 dodatku).
+=
jest mniej ” hałaśliwe ” (również powód, dla którego unikam Integer.toString()
) i wygrał ' nie robi dużej różnicy, ponieważ istnieją ' co najwyżej dwa konkatenacje . Btw .: ' d użyłem StringBuilder w następujący sposób: zadeklaruj przed pętlą, zainicjuj z pojemnością ustawioną na 8
, wyczyść i użyj ponownie iteracja. Utworzenie go w pętli nie ' nie poprawiłoby znacznie. StringBuilder
– ale tylko jedno połączenie z System.out.println(...)
.