1

问题是关于 while 循环,其中我需要执行 N 次代码和 N+1 次其他代码。不是关于连接字符串,我只是将其用作错误编码但简短的示例。

让我通过提供一个例子来解释我的问题。

假设我想连接 N+1 个字符串,例如用“\n”粘合它们。那时我会有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();
}

要删除重复项,您也可以通过在循环内部进行检查来做到这一点,但是我发现这很愚蠢,因为我事先知道检查是预先确定的,因为它只会在第一次迭代时为假:

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

是否有任何解决方案,一种使用 codeA() 初始化一次然后继续循环 codeB() 和 codeA() 的 while 循环?

我猜人们以前一定遇到过这种情况。只是想知道是否有任何漂亮的解决方案。

4

4 回答 4

1

令我失望的是,我相信没有这样的结构可以满足您所说的条件,我将尝试解释原因(尽管我无法以严格的数学方式证明)。

问题的要求是:

  1. 我们有两部分代码:codeA()codeB()
  2. 这两个部分执行的次数不同,N 和 N+1
  3. 我们希望避免在循环内添加条件
  4. 我们希望每个部分只执行严格必要的次数

2) 是 1) 的直接结果。如果我们没有两部分代码,我们就不需要不同数量的执行。我们将有一个循环体。

4) 又是 1) 的结果。如果我们只有一个循环体,就没有多余的执行。我们可以通过循环的条件来控制它的执行

所以限制基本上是1)和3)。

现在在循环中,我们需要在每次迭代中回答两个问题:a) 我们执行了codeA()吗?b) 我们执行codeB()吗?我们根本没有足够的信息来决定,因为我们只有一个条件(循环的条件),并且该条件将用于决定两个代码部分是否都将被执行。

所以我们需要打破 1) 和/或 3) 要么我们在循环中添加额外的条件,要么我们将决定委托给其他代码(因此不再有两个部分)。

显然,委托的一个例子可能是(我正在使用字符串连接示例):

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

注意:通常有一种很好的方法可以避免在所有处理这些行时都需要创建此字符串。没有更多的上下文很难说。

于 2013-07-18T12:45:11.517 回答
0

就我个人而言,我大部分时间都有同样的问题,在 String 示例中,我使用了 StringBuilder,就像你说的那样,只是删除了添加的字符:

StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
    sb.append(array[i]).append("\n");
}
sb.delete(sb.length-1, sb.length);  // maybe check if sb contains something

在常见的情况下,我想除了添加如果你建议之外别无他法。为了使代码更清晰,我会在 for 循环结束时检查:

StringBuilder sb = new StringBuilder();
for(int i=0; i<N; i++) {
    sb.append(array[i]);
    if(i < N) {
         sb.append("\n");
    }
}

但我完全同意,有这种双重逻辑是可悲的

于 2013-07-18T13:05:41.357 回答
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' 的数组,当所需的输出为:

第 1 行\n第 2 行。

我提供的示例很清楚,并且表现不佳。事实上,使用 StringBuilder/Buffer 可以获得更大的性能提升。拥有清晰的代码对于专业人士来说是必不可少的。

于 2013-07-18T12:46:48.173 回答