Běžná implementace FizzBuzz , kterou jsem viděl, používá šek na% 15 pro tisk „FizzBuzz“

Dali byste mi vědět, jestli je s tímto přístupem něco špatného / lepšího?

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)); } } } } 

Komentáře

  • Vaše verze je optimalizována pro počítač. Verze Winston ‚ s je optimalizována pro člověka. Musím důvěřovat kompilátoru, že dokáže dobře promíchat a optimalizovat kód. Je také možné, že jeden příkaz io bude fungovat rychleji než dva samostatné. Měli byste závodit s vaší verzí proti té druhé.
  • Řeknu vám, proč se mi moje verze líbí lépe (pouze pro kontext rozhovoru). 1) udržovatelnost – můžete Fizz a Buzz externalizovat jako řetězce, nemusíte ‚ externalizovat FizzBuzz 2) DRY, uživatel, který píše výše uvedený kód, přemýšlí o tom, že se nebude opakovat, což se mi líbí
  • +1, ale použijte StringBuilder a ne 100 * System.out.println (..) a Integer.valueOf (i)
  • @ cl-r díky, ponechám to na originále, takže komentáře budou mít stále smysl, díky za zpětnou vazbu
  • FizzBuzzEnterpriseEdition je nejlepší implementace, která existuje: github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition ; D

Odpověď

Pojďme porovnat vaši verzi s % 15 verzí:

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 verze je sim plnější a snadněji čitelný. Tato verze přehledně definuje problém do 4 různých případů a zpracovává každý případ. Naproti tomu vaše verze zavádí logický logický příznak (který považuji za významný anti-vzor) a ne zcela intuitivní závislost na pořadí příkazů if.

Komentáře

  • 15 je “ magické číslo “ zde. Místo toho ‚ navrhuji použít (3 * 5). Kompilátor by jej měl podle tohoto kritéria převést na 15 …
  • @Ron – ano, "FizzBuzz". Ne že byste ‚ re špatně nutně, ale pro tyto typy ‚ trivia ‚ otázky, nutnost deklarovat vše je obvykle mírně uvolněná. Například, přísně vzato, u kódu na úrovni produkce by všechna čísla a řetězce, na které se zde odkazuje / tiskly, měla být zachycena jako pojmenované konstanty.
  • @ X-Zero, zachytili byste 3 jako konstanta, jak by se jí dalo říkat?
  • @Winston – Obecným problémem je to, že ‚ s je v podstatě ‚ vymyslel ‚ příklad, takže může být těžké získat dobrá jména. Zejména proto, že test má v podstatě ‚ více ‚ kontrol – další rozklad by pravděpodobně vedl k nějaké struktuře pole / tabulky (jo … já vím … směřující k vesmírné architektuře). Takže MATCH možná? CONDITION? Urgh. Což je důvod, proč jsou tyto druhy konvencí pro tyto druhy testů uvolněné; test je zaměřen na základní schopnost kódování, nikoli (nutně) na úplné abstrakční dovednosti.
  • Přesunul bych if-for-15 uvnitř if-for-5, pokud můžete ‚ t rozdělí číslo na 3, určitě ‚ t rozdělí na 15, uloží 4/5 šeků na všechna čísla

Odpověď

Vypadá to dobře. String.valueOf() je zbytečné, System.out.println(i) by tisklo to samé, ale stále je to v pořádku. Tento test se používá pouze k zajištění toho, aby dotazovaný mohl psát kód, jak říká odkazovaný web:

Tento druh otázky neidentifikuje skvělé programátory, ale identifikuje slabé. A to je určitě krok správným směrem.

Odpovědět

Oni rozhodně nejsou dokonalosti, ale vyzkoušel jsem několik způsobů, jak optimalizovat test, zde je výsledek (měl jsem čísla, abych udržel stopu dobrých odpovědí) a používám StringBuilder, abych se vyhnul inicializaci výstupního 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; } } } 

A výstup:

------ 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 

Komentáře

  • StringBuilder je založen na char[16]. Počáteční kapacitu byste měli nastavit na hodnotu větší než String, který chcete vytvořit – nebo zhoršíte výkon, protože StringBuilder musí růst (přidělte nové char[], zkopírujte stará data). Měli byste také vědět, jak [System.nanoTime()] (stas-blogspot.blogspot.com /2012/02/what-is-behind-systemnanotime.html) funguje a problémy, které má.A ‚ doporučuji vám udělat mnohem více iterací. Myslím, že právě teď měříte čas System.out.println(), ostatní operace pravděpodobně trvají ve srovnání se systémovým voláním velmi málo času.
  • Řekněte mi, už jste někdy Slyšeli jste o konceptu Over-Engineering …?
  • @Max, co dělám, ale je tento web určen pro některé výzkumy nebo ne? Je pro pohodlné oči nebo se snaží pochopit, jak jsou některé způsoby lepší? Můžete si tedy vybrat a porovnat rychlejší, snadno čitelný nebo dotazovat kód a najít chybějící optimalizaci.
  • Viz Pravidla pro optimalizaci . Nejlepší odpověď poskytl IMHO Winston Ewert.
  • vysvětlete matematiku pomocí kódu tabulky, prosím?

odpověď

Tady je jeho verze (IMHO) o něco lepší pro lidi než ta vaše a lepší také pro počítače:

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); } } } 

Komentáře poskytují informace lidem (ale i tak to mohli vidět sami) a na System.out.println volání stačí i.

EDIT: Toto je další způsob fizz-buzz (focus: 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); } } } 

EDIT 2: ještě další pomocí StringBuilder, SUCHÉ také:

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); } } 

Komentáře

  • StringBuilder se zdá být rychlejším přístupem než + = v tomto případě
  • @EranMedan – jste si tím jisti? StringBuilder je dobrý, protože N přidává nemá

t nevede kNalokacím, zde všakNje maximálně 2, což je dostatečně malé číslo, které pravděpodobně ‚ t nezmění, a ‚ bude pravděpodobně 1, což znamená žádný rozdíl za vše (nebo možná ještě horší, protožeStringBuilderpravděpodobně přiděluje další přidělení pro tuto 1 přílohu).

  • @asveikau – máte pravděpodobně pravdu, myslím, že to bude přes optimalizaci, abych zjistil, co je rychlejší 🙂
  • Jsem si ‚ vědom StringBuilder – který po celou dobu používám v těžkém kódu String – a přemýšlel jsem řádky asveikau . += je méně “ hlučný “ (také důvod, proč jsem se vyhnul Integer.toString()) a ‚ nebude mít velký rozdíl, protože ‚ maximálně dvě zřetězení . Btw .: Použil jsem ‚ StringBuilder takto: deklarovat před smyčkou, inicializovat s kapacitou nastavenou na 8, vymazat a znovu použít za opakování. Jeho vytvoření uvnitř smyčky by ‚ příliš nezlepšilo.
  • viz výše pro další verzi používající StringBuilder – ale pouze jedno volání na System.out.println(...).
  • Napsat komentář

    Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *