A implementação FizzBuzz comum que vi está usando uma verificação de% 15 para imprimindo “FizzBuzz”

Você poderia me informar se houver algo de errado / melhor com essa abordagem?

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

Comentários

  • Sua versão é otimizada para o computador. A versão de Winston ‘ s é otimizada para humanos. Tenho que confiar em um compilador que ele pode fazer um bom trabalho ao reorganizar e otimizar o código. Além disso, é possível que uma única instrução io funcione mais rápido do que duas separadas. Você deve competir com a sua versão contra a outra.
  • Eu ‘ direi porque gosto mais da minha versão (apenas para o contexto da entrevista) 1) facilidade de manutenção – você pode externalizar Fizz e Buzz como strings, você não ‘ não precisa externalizar FizzBuzz 2) DRY, um usuário escrevendo o código acima está pensando em não se repetir, o que eu gosto
  • +1, mas use um StringBuilder e não 100 * System.out.println (..) e Integer.valueOf (i)
  • @ cl-r obrigado, vou mantê-lo no original para que os comentários ainda façam sentido, obrigado pelo feedback
  • FizzBuzzEnterpriseEdition é a melhor implementação que existe: github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition ; D

Resposta

Vamos comparar sua versão com a % 15 versão:

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

O % 15 a versão é sim mais simples e mais fácil de ler. Esta versão delineia perfeitamente o problema em 4 casos diferentes e trata cada caso. Em contraste, sua versão apresenta um sinalizador de lógica booleana (que considero um anti-padrão significativo) e uma dependência não totalmente intuitiva da ordem das instruções if.

Comentários

  • 15 é um ” número mágico ” aqui. Eu ‘ d sugiro usar (3 * 5) em seu lugar. O compilador deve convertê-lo para 15 …
  • @Ron – Então é, "FizzBuzz", por este critério. Não que você ‘ re errado necessariamente, mas para esses tipos de ‘ trivialidades ‘ perguntas, a necessidade de declarar tudo é geralmente relaxada um pouco. Por exemplo, estritamente falando, para código de nível de produção, todos os números e strings referenciados / impressos aqui devem ser capturados como constantes nomeadas.
  • @ X-Zero, você capturaria o 3 como uma constante, como você o chamaria?
  • @Winston – O problema geral com isso é que ‘ é basicamente um ‘ inventado ‘ exemplo, então pode ser difícil conseguir nomes bons para isso. Especialmente porque o que o teste tem são essencialmente ‘ múltiplas ‘ verificações – continuar a decompor isso provavelmente resultaria em algum tipo de estrutura de matriz / tabela (sim … eu sei … indo para a arquitetura do espaço sideral). Então, MATCH talvez? CONDITION? Urgh. É por isso que esses tipos de convenções são relaxados para esses tipos de testes; o teste é para habilidades básicas de codificação, não (necessariamente) habilidades de abstração total.
  • Eu moveria if-for-15 dentro de if-for-5, se você puder ‘ t dividir um número por 3, certamente não pode ‘ t dividir por 15, economize 4/5 de cheques para todos os números

Resposta

Parece bom. String.valueOf() é desnecessário, System.out.println(i) imprimiria o mesmo, mas ainda está OK. Este teste é usado apenas para garantir que o entrevistado possa escrever o código conforme o site vinculado diz:

Este tipo de pergunta não identifica grandes programadores, mas vai identificar os fracos. E isso é definitivamente um passo na direção certa.

Resposta

Eles certamente não são perfeitos, mas eu tentei algumas maneiras de otimizar o teste, aqui está o resultado (eu tive números para manter o rastreamento de boas respostas), e eu uso um StringBuilder para evitar a inicialização da saída 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; } } } 

E a saída:

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

Comentários

  • StringBuilder é baseado em um char[16]. Você deve definir a capacidade inicial para um valor maior do que a String que deseja criar – ou piora o desempenho, pois StringBuilder tem que crescer (alocar novos char[], copiar dados antigos). Você também deve estar ciente de como [System.nanoTime()] (stas-blogspot.blogspot.com /2012/02/what-is-behind-systemnanotime.html) funciona e os problemas que tem.E eu ‘ d aconselho você a fazer muito mais iterações. Acho que você mede principalmente o tempo para System.out.println() agora, as outras operações provavelmente levam muito pouco tempo em comparação com uma chamada de sistema.
  • Diga-me, você já já ouviu falar do conceito over-engineering …?
  • @Max sim, mas este site é feito para algumas pesquisas ou não? É para olhos confortáveis, ou para tentar entender como alguns aspectos são melhores? Assim, você pode escolher e comparar o mais rápido, o fácil de ler ou interrogar o código para encontrar a otimização ausente.
  • Consulte Regras para otimização . IMHO Winston Ewert forneceu a melhor resposta.
  • explique matemática em código com tabela, por favor?

Resposta

Aqui está uma versão que “é (IMHO) um pouco melhor para humanos do que a sua e melhor para computadores também:

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

Os comentários fornecem informações para humanos (mas eles ainda podiam ver por conta própria) e há apenas uma System.out.println chamada por i.

EDITAR: Esta é outra maneira de fazer barulho (foco: 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); } } } 

EDITAR 2: ainda outro, usando StringBuilder, DRY também:

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

Comentários

  • StringBuilder parece uma abordagem mais rápida do que + = neste caso
  • @EranMedan – Tem certeza disso? StringBuilder é bom porque N acrescenta não

t leva aNalocações, entretanto aquiNé no máximo 2, que é um número pequeno o suficiente para que provavelmente ‘ fizesse diferença e ‘ provavelmente seria 1, o que significa que não há diferença em todos (ou talvez pior, já queStringBuilderprovavelmente faz uma alocação extra para aquele anexo 1).

  • @asveikau – você provavelmente está certo, acho que isso será sobre a otimização para descobrir exatamente o que é mais rápido 🙂
  • Eu ‘ estou ciente do StringBuilder – que uso o tempo todo em códigos pesados de String – e pensei muito as linhas de asveikau . += é menos ” noisy ” (também a razão para evitar Integer.toString()) e ganhou ‘ t faz muita diferença, pois há ‘ no máximo duas concatenações . A propósito: eu ‘ d usei StringBuilder assim: declare antes do loop, inicialize com capacidade definida para 8, apague e reutilize por iteração. Criá-lo dentro do loop ‘ não melhoraria muito.
  • veja acima para outra versão usando StringBuilder – mas apenas uma chamada para System.out.println(...).
  • Deixe uma resposta

    O seu endereço de email não será publicado. Campos obrigatórios marcados com *