私が見た一般的な FizzBuzz の実装では、%15のチェックを使用しています。 「FizzBuzz」の印刷
このアプローチに問題があるか、より良い点があるかどうか教えていただけますか?
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)); } } } }
コメント
- お使いのバージョンはコンピューター用に最適化されています。 Winston 'のバージョンは人間向けに最適化されています。コードの再シャッフルと最適化に優れた仕事をすることができるコンパイラを信頼するようになりました。また、1つのioステートメントが2つの別々のステートメントよりも高速に動作する可能性があります。自分のバージョンを他のバージョンと競合させる必要があります。
- I '自分のバージョンの方が好きな理由を説明します(インタビューのコンテキストのみ)1)保守性- FizzとBuzzを文字列として外部化でき、' FizzBuzzを外部化する必要はありません2)DRY、上記のコードを書いているユーザーは、自分自身を繰り返さないという観点から考えています。
- +1ただし、100ではなく StringBuilder を使用します* System.out.println(..)、および Integer.valueOf(i)
- @ cl-rありがとうございます。コメントは引き続き意味があるので、元の状態を維持します。フィードバックに感謝します。
- FizzBuzzEnterpriseEditionは、最適な実装です: github.com/EnterpriseQualityCoding/FizzBuzzEnterpriseEdition ; D
回答
バージョンを% 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
バージョンはsimですしなやかで読みやすい。このバージョンは、問題を4つの異なるケースにきちんと描写し、それぞれのケースを処理します。対照的に、お使いのバージョンでは、ブール論理フラグ(これは重要なアンチパターンだと思います)が導入されており、ifステートメントの順序に完全に直感的に依存しているわけではありません。
コメント
- 15は"マジックナンバー"ここ。 '代わりに
(3 * 5)
を使用することをお勧めします。コンパイラはそれを15に変換する必要があります… - @ Ron-つまり、
"FizzBuzz"
はこの基準によってです。 'が必ずしも間違っているというわけではありませんが、これらのタイプの'雑学クイズ'の質問ですが、すべてを宣言する必要性は通常少し緩和されます。たとえば、厳密に言えば、本番レベルのコードの場合、ここで参照/印刷されるすべての数値と文字列は名前付き定数としてキャプチャする必要があります。 - @ X-Zero、キャプチャしますか3を定数として、何と呼びますか?
- @ Winston-これに関する一般的な問題は、'基本的に'考案された'の例であるため、このための適切な名前を取得するのは難しい場合があります。特に、テストの内容は基本的に'複数の'チェックであるため、これを分解し続けると、何らかの配列/テーブル構造になる可能性があります。 (ええ…私は知っています…宇宙建築に向かっています)。それで、
MATCH
多分?CONDITION
?うーん。そのため、これらの種類の規則は、これらの種類のテストでは緩和されています。テストは基本的なコーディング能力を対象としており、(必然的に)完全な抽象化スキルではありません。 - 可能であれば、if-for-15をif-for-5内に移動します' tは数値を3で除算しますが、' 15で除算することはできません。すべての数値のチェックの4/5を節約できます
回答
問題ないようです。 String.valueOf()
は不要です。System.out.println(i)
でも同じように出力されますが、それでも問題ありません。このテストは、リンク先のサイトにあるように、インタビュー対象者がコードを記述できることを確認するためにのみ使用されます。
この種の質問では、優れたプログラマーを特定できません。しかし、それは弱いものを識別します。そして、それは間違いなく正しい方向への一歩です。
回答
彼ら確かに完璧ではありませんが、テストを最適化するためのいくつかの方法を試しました。ここでは結果(良好な応答を追跡するための数値があります)、および出力IOの初期化を回避するためにStringBuilderを使用しています。
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; } } }
そして出力:
------ 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
コメント
- StringBuilderは
char[16]
に基づいています。初期容量を、作成する文字列よりも大きい値に設定する必要があります。そうしないと、StringBuilderを拡張する必要があるため、パフォーマンスが低下します。 (新しいchar[]
を割り当て、古いデータをコピーします)。[System.nanoTime()
](stas-blogspot.blogspot.com)の方法にも注意する必要があります。 /2012/02/what-is-behind-systemnanotime.html)が機能し、問題が発生します。そして、'もっと多くの反復を行うことをお勧めします。現在、主にSystem.out.println()
の時間を測定していると思いますが、他の操作はシステムコールに比べておそらくほとんど時間がかかりません。 - 教えてください。 オーバーエンジニアリング …?
- @Maxという概念を聞いたことがありますが、このサイトはいくつかの研究のために作成されたものですか?快適な目のためですか、それともいくつかの方法がより良いかを理解しようとするためですか?そのため、コードを選択して比較し、より速く、読みやすく、またはコードを調べて、不足している最適化を見つけることができます。
- 最適化のルールを参照してください。 。 IMHO WinstonEwertがベストアンサーを提供しました。
- withTableコードで数学を説明してください?
アンサー
ここにあるバージョン(IMHO)は、人間にとってはあなたよりも少し優れており、コンピューターにとっても優れています:
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); } } }
コメントは情報を提供します人間に対して(ただし、それでも自分で見ることができます)、i
ごとにSystem.out.println
の呼び出しは1つだけです。
編集:これはfizz-buzzのもう1つの方法です(フォーカス: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); } } }
編集2: 、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); } }
コメント
- StringBuilderはより高速なアプローチのようです+ =よりもこの場合
- @ EranMedan-よろしいですか?
N
が追加されるため、StringBuilder
は適切です。しない
はN
の割り当てにつながりますが、ここではN
は最大2であり、これは十分に小さいため、'違いはありません。また、'は1である可能性が非常に高いため、すべて(または、おそらくStringBuilder
がその1つの追加に対して追加の割り当てを行うため、さらに悪いことになります)。
+=
は"ノイズが少ない"(
)、最大2つの連結があるため、'大きな違いはありません' 。ところで:私は'次のようにStringBuilderを使用しました:ループの前に宣言し、容量を8
に設定して初期化し、クリアして再利用します。反復。ループ内で作成しても、'あまり改善されません。
StringBuilder
を使用した別のバージョンについては、上記を参照してください。 System.out.println(...)
への1回の呼び出し。