Limplémentation courante FizzBuzz que jai vue utilise une vérification de% 15 pour impression « FizzBuzz »

Pourriez-vous me faire savoir sil y a quelque chose de mal / mieux avec cette approche?

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

Commentaires

  • Votre version est optimisée pour lordinateur. La version de Winston ‘ est optimisée pour lhumain. Il faut faire confiance à un compilateur pour quil puisse faire un bon travail de remaniement et doptimisation du code. En outre, il est possible quune seule instruction io fonctionne plus rapidement que deux autres. Vous devriez faire la course entre votre version et lautre.
  • Je ‘ vous expliquerai pourquoi jaime mieux ma version (uniquement pour le contexte de linterview) 1) maintenabilité – vous pouvez externaliser Fizz et Buzz sous forme de chaînes, vous navez ‘ pas besoin dexternaliser FizzBuzz 2) DRY, un utilisateur qui écrit le code ci-dessus pense en termes de ne pas se répéter, ce que jaime
  • +1 mais, utilisez un StringBuilder et non 100 * System.out.println (..), et, Integer.valueOf (i)
  • @ cl-r merci, je vais le garder à loriginal pour que les commentaires aient toujours du sens, merci pour les commentaires
  • FizzBuzzEnterpriseEdition est la meilleure implémentation qui soit: github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition ; D

Réponse

Comparons votre version à la version % 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)); } } } } 

Le % 15 la version est sim pler et plus facile à lire. Cette version délimite parfaitement le problème dans les 4 cas différents et gère chaque cas. En revanche, votre version introduit un drapeau logique booléen (que je considère comme un anti-pattern significatif) et une dépendance pas entièrement intuitive sur lordre des instructions if.

Commentaires

  • 15 est un  » nombre magique  » ici. Je ‘ suggère d’utiliser (3 * 5) à la place. Le compilateur doit le convertir en 15 …
  • @Ron – Il en est de même, "FizzBuzz", selon ce critère. Non pas que vous ‘ avez tort nécessairement, mais pour ces types de ‘ trivia ‘ questions, la nécessité de tout déclarer est généralement légèrement assouplie. Par exemple, à proprement parler, pour le code de production, tous les nombres et les chaînes référencés / imprimés ici doivent être capturés comme des constantes nommées.
  • @ X-Zero, voulez-vous capturer le 3 comme une constante, comment lappellerais-tu?
  • @Winston – Le problème général avec ceci est que ‘ est fondamentalement un ‘ artificiel ‘ exemple, il peut donc être difficile d’obtenir de bons noms pour cela. Dautant plus que le test contient essentiellement des vérifications ‘ multiples ‘ – continuer à décomposer cela entraînerait probablement une sorte de structure de tableau / tableau (ouais … je sais … en direction de larchitecture spatiale). Alors, MATCH peut-être? CONDITION? Urgh. Cest pourquoi ces types de conventions sont assouplis pour ces types de tests; le test concerne la capacité de codage de base, pas (nécessairement) des compétences dabstraction complètes.
  • Je déplacerais if-for-15 à lintérieur de if-for-5, si vous pouvez ‘ t divise un nombre par 3, peut certainement ‘ t diviser par 15, économisez 4/5 de chèques pour tous les nombres

Réponse

Ça a lair bien. String.valueOf() nest pas nécessaire, System.out.println(i) afficherait la même chose mais cest toujours OK. Ce test est utilisé uniquement pour sassurer que la personne interrogée peut écrire du code comme lindique le site lié:

Ce type de question nidentifiera pas les grands programmeurs, mais il identifiera les faibles. Et cest définitivement un pas dans la bonne direction.

Réponse

Ils ne sont certes pas parfaits, mais jai essayé quelques moyens pour optimiser le test, voici le résultat (jai eu des nombres pour garder trace des bonnes réponses), et jutilise un StringBuilder pour éviter linitialisation de la sortie 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; } } } 

Et la sortie:

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

Commentaires

  • StringBuilder est basé sur un char[16]. Vous devez définir la capacité initiale sur une valeur supérieure à la chaîne que vous souhaitez créer – ou vous détériorez les performances, car StringBuilder doit croître (allouez de nouveaux char[], copiez les anciennes données). Vous devez également savoir comment [System.nanoTime()] (stas-blogspot.blogspot.com /2012/02/what-is-behind-systemnanotime.html) fonctionne et les problèmes quil a.Et je ‘ vous conseille de faire beaucoup plus ditérations. Je pense que vous mesurez principalement le temps pour System.out.println() en ce moment, les autres opérations prennent probablement très peu de temps par rapport à un appel système.
  • Dites-moi, avez-vous déjà entendu parler du concept sur-ingénierie …?
  • @Max je le fais, mais ce site est-il fait pour certaines recherches ou pas? Est-ce pour des yeux confortables ou pour essayer de comprendre comment certaines méthodes sont meilleures? Ainsi, vous pouvez choisir et comparer le plus rapide, le plus facile à lire, ou interroger le code pour trouver loptimisation manquante.
  • Voir Règles doptimisation . IMHO Winston Ewert a fourni la meilleure réponse.
  • expliquer les mathématiques en code avec le code de la table sil vous plaît?

Réponse

Voici « une version qui » est (à mon humble avis) un peu meilleure pour les humains que la vôtre et meilleure pour les ordinateurs également:

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

Les commentaires fournissent des informations aux humains (mais ils pouvaient toujours le voir par eux-mêmes) et il ny a quun seul appel System.out.println par i.

EDIT: Voici une autre façon de faire pétiller le 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: encore un autre, en utilisant StringBuilder, DRY aussi:

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

Commentaires

  • StringBuilder semble une approche plus rapide than + = dans ce cas
  • @EranMedan – En êtes-vous sûr? StringBuilder est bon car N ajoute ne

t conduit à des allocationsN, mais iciNest au plus 2, ce qui est un un nombre suffisamment petit pour que ‘ t fasse une différence, et il ‘ est probablement 1, ce qui signifie qu’il n’y a pas de différence à tout (ou peut-être pire, carStringBuilderfait probablement une allocation supplémentaire pour cet ajout).

  • @asveikau – vous avez probablement raison, je suppose que ce sera sur loptimisation pour savoir exactement ce qui est le plus rapide 🙂
  • Je ‘ suis conscient de StringBuilder – que jutilise tout le temps dans le code lourd String – et jai réfléchi les lignes de asveikau . += est moins  » bruyant  » (également la raison pour laquelle jai évité Integer.toString()) et cela na pas ‘ faire une grande différence car il y a ‘ au plus deux concaténations . Btw .: Jai ‘ avoir utilisé StringBuilder comme ceci: déclarer avant la boucle, initialiser avec une capacité définie sur 8, effacé et réutiliser par itération. Le créer à lintérieur de la boucle ne ‘ saméliorerait pas beaucoup.
  • voir ci-dessus pour une autre version utilisant StringBuilder – mais seulement un appel à System.out.println(...).
  • Laisser un commentaire

    Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *