1

問題は、いくつかのコードを N 回実行し、他のコードを N+1 回実行する必要がある while ループに関するものです。文字列の連結についてではなく、これを悪いコードで短い例として使用します。

例を挙げて私の質問を説明しましょう。

たとえば、「\ n」で接着して、N + 1個の文字列を連結したいとします。その場合、N+1 行のテキストになりますが、「\n」を N 回追加するだけで済みます。

一部のコードを N 回実行し、他のコードを N+1 回実行する必要がある、このタイプのループのボイラープレート ソリューションはありますか? 文字列を連結するための解決策を求めているのではありません! それは単なる(悪い)例です。私は一般的な解決策を探しています。

これに関する問題はコードの重複であるため、例をコーディングするには、次のようにします (悪い疑似コード、StringBuilder などを使用する必要があることはわかっています)。

String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
    total += "\n" + lines[i];
}

もちろん、N+1 回実行する必要があるコードが大きくなると、問題はさらに悪化します。それから私は次のようなことをします

codeA(); // adding the line of text
for (int i = 1; i < N + 1; i++){
    codeB(); // adding the "\n"
    codeA();
}

重複を削除するには、ループ内でチェックすることによってこれを別の方法で行うこともできますが、最初の繰り返しでのみ false になるため、チェックが事前に決定されていることを事前に知っているため、これは非常に愚かです。

for (int i = 0; i < N + 1; i++){
    if (i > 0){
        codeB(); // adding the "\n"
    }
    codeA();
}

これに対する解決策はありますか?

人々は以前にこれに出くわしたにちがいないと思います。これに対する美しい解決策があるかどうか疑問に思っています。

4

4 に答える 4

1

残念なことに、あなたが述べたような条件を満足するような構造はないと信じており、その理由を説明しようと思います (ただし、厳密に数学的な方法で証明することはできません)。

問題の要件は次のとおりです。

  1. コードには次の 2 つの部分がありますcodeA()codeB()
  2. 2 つの部分は異なる回数 (N と N+1) 実行されます。
  3. ループ内に条件を追加することは避けたい
  4. 各部分を厳密に必要な回数だけ実行したい

2) は 1) の直接的な結果です。コードの 2 つの部分がなければ、実行回数を変える必要はありません。単一のループ本体があります。

4) も 1) の結果です。単一のループ本体がある場合、冗長な実行はありません。ループの条件を通じてその実行を制御できます

したがって、制限は基本的に 1) と 3) です。

ループ内で、反復ごとに 2 つの質問に答える必要がありますcodeA()。b) 実行しcodeB()ますか? 単一の条件 (ループの条件) しかなく、その条件を使用して両方のコード部分が実行されるかどうかを決定するため、決定するのに十分な情報がありません。

したがって、1) および/または 3) を中断する必要があります。ループ内に余分な条件を追加するか、決定を他のコードに委譲します (したがって、2 つの部分がなくなります)。

どうやら委任の例は次のようになります (文字列連結の例を使用しています)。

String [] lines = ...
for (int i = 0; i < N; i++){
   // delegate to a utility class LineBuilder (perhaps an extension of StringBuilder) to concatenate lines
   // this class would still need to check a condition e.g. for the first line to skip the "\n"
   // since we have delegated the decisions we do not have two code parts inside the loop
   lineBuilder.addLine( lines[i] );
}

ここで、委任のより興味深いケースは、決定をデータ自体に委任できる場合です(これは覚えておく価値があるかもしれません)。例:

List<Line> lines = Arrays.asList(
             new FirstLine("Every"),    // note this class is different
             new Line("word"), 
             new Line("on"), 
             new Line("separate"), 
             new Line("line") );

StringBuffer sb = new StringBuffer();

for (Line l : lines) {
    // Again the decision is delegated. Data knows how to print itself
    // Line would return: "\n" + s
    // FirstLine would return: s
    sb.append( l.getPrintVersion() );
}

もちろん、上記のすべてが、問題を解決しようとするクラスを実装できないという意味ではありません。これは元の質問の範囲を超えていると思いますが、単純なループではやり過ぎになることは言うまでもありません

于 2013-07-18T19:26:41.523 に答える
0

このように文字列を連結することは悪い考えであり、私見よりもはるかに大きな問題です。

しかし、あなたの質問に答えるために私はします

String sep = "";
StringBuilder sb= new StringBuilder();
for(String s: lines) {
    sb.append(sep).append(s);
    sep = "\n";
}
String all = sb.toString();

注: 通常、取得した行を処理する際に、この String を作成する必要がないようにする良い方法があります。これ以上の文脈なしに言うのは難しいです。

于 2013-07-18T12:45:11.517 に答える
0

この種のことは、SQL をビルドするときのように、かなり一般的です。これは私が従うパターンです:

String[] lines ...//init somehow;
String total = lines[0];
boolean firstTime = true;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++){
    if(firstTime) firstTime = false;
    else sb.append('\n');

    sb.append(lines[i]);
}

これは最初の例と同じではないことに注意してください。理由は次のとおりです。

String[] lines = <some array of dimension N+1>;
String total = lines[0];
for (int i = 1; i < N + 1; i++){
    total += "\n" + lines[i];
}

[0] = 'line1' および [1] = 'line2' の配列があると仮定すると、目的の出力が次の場合、最終的に line1line2\n になります。

ライン1\nライン2.

私が提供した例は明確で、パフォーマンスも悪くありません。実際、StringBuilder/Buffer を利用すると、パフォーマンスが大幅に向上します。明確なコードを持つことは、プロにとって不可欠です。

于 2013-07-18T12:46:48.173 に答える