【问题标题】:Last iteration of enhanced for loop in javajava中增强for循环的最后一次迭代
【发布时间】:2010-09-22 01:56:15
【问题描述】:

有没有办法确定循环是否是最后一次迭代。我的代码如下所示:

int[] array = {1, 2, 3...};
StringBuilder builder = new StringBuilder();

for(int i : array)
{
    builder.append("" + i);
    if(!lastiteration)
        builder.append(",");
}

现在问题是我不想在最后一次迭代中附加逗号。现在有没有办法确定它是最后一次迭代,还是我坚持使用 for 循环或使用外部计数器来跟踪。

【问题讨论】:

  • 是的!很有趣,我只是想问完全相同的问题!
  • 同样的问题会回来(而且会如此)。现在,如果一个元素需要不同的处理,为什么要创建一个循环? stackoverflow.com/questions/156650/…
  • 既然你有一个固定的数组,为什么要使用增强型呢? for(int i = 0; i

标签: java for-loop foreach conditional-execution


【解决方案1】:

总是追加可能更容易。然后,当您完成循环后,只需删除最后一个字符。这样也少了很多条件。

您可以使用StringBuilderdeleteCharAt(int index),索引为length() - 1

【讨论】:

  • 这个问题最有效的解决方案。 +1。
  • 也许是我,但我真的不喜欢你正在删除你刚刚添加的东西......
  • Fortega:我不喜欢每次都检查我 99% 都会做的事情。应用 Dinah 或 sblundy 的解决方案似乎更合乎逻辑(而且速度更快)。
  • 我认为最优雅的解决方案。谢谢!
【解决方案2】:

如果你把它转换成一个经典的索引循环,是的。

或者您可以在完成后删除最后一个逗号。像这样:

int[] array = {1, 2, 3...};
StringBuilder

builder = new StringBuilder();

for(int i : array)
{
    builder.append(i + ",");
}

if(builder.charAt((builder.length() - 1) == ','))
    builder.deleteCharAt(builder.length() - 1);

我,我只是使用commons-lang 中的StringUtils.join()

【讨论】:

    【解决方案3】:

    保持简单并使用标准的 for 循环:

    for(int i = 0 ; i < array.length ; i ++ ){
        builder.append(array[i]);
        if( i != array.length - 1 ){
            builder.append(',');
        }
    }
    

    或者只使用 apache commons-lang StringUtils.join()

    【讨论】:

      【解决方案4】:

      显式循环总是比隐式循环更好。

      builder.append( "" + array[0] );
      for( int i = 1; i != array.length; i += 1 ) {
         builder.append( ", " + array[i] );
      }
      

      您应该将整个内容包装在一个 if 语句中,以防万一您正在处理一个零长度数组。

      【讨论】:

      • 我喜欢这种方法,因为它不需要在每次迭代中执行测试。我唯一要补充的是builder可以直接附加整数,因此不需要使用“”+ int,只需附加(数组[0])。
      • 如果围绕整个批次,您还需要一个以确保数组至少包含一个元素。
      • 为什么每个人都在 append 的内部继续使用字符串连接的示例? ", " + x 编译成 new StringBuilder(", ").append( x ).toString()...
      • @Josh 和@John:按照 n00b 示例。不想一次介绍太多东西。但是,您的观点非常好。
      • @Tom:对。我想我已经说过了。无需修改。
      【解决方案5】:

      另一种选择是在附加 i 之前附加逗号,而不是在 first 迭代中。 (顺便说一句,请不要使用"" + i - 你真的不想在这里进行连接,而且 StringBuilder 有一个非常好的 append(int) 重载。)

      int[] array = {1, 2, 3...};
      StringBuilder builder = new StringBuilder();
      
      for (int i : array) {
          if (builder.length() != 0) {
              builder.append(",");
          }
          builder.append(i);
      }
      

      这样做的好处是它可以与任何Iterable 一起使用——你不能总是索引东西。 (当您真正使用 StringBuilder 时,“添加逗号然后在末尾删除它”是一个不错的建议 - 但它不适用于写入流之类的事情。不过,这可能是解决这个确切问题的最佳方法。 )

      【讨论】:

      • 很好的模式,但是 builder.length() != 0 很脆弱——想象一下在循环之前将某些东西(有条件地!)添加到缓冲区中。相反,请使用 isFirst 布尔标志。奖励:也更快。
      • @Jason:我当然使用“isFirst”模式,其中构建器在第一次迭代时不会为空。但是,根据我的经验,当不需要它时,它会给实现增加相当多的臃肿。
      • @Liverpool (etc):1000 次不必要的检查非常,非常不太可能对性能产生任何重大影响。我可能同样指出,Dinah 的解决方案添加的额外字符 可能 导致 StringBuilder 必须扩展,最终字符串的大小加倍 (cont)
      • 不必要的缓冲空间。然而,重要的一点是可读性。我碰巧发现我的版本比 Dinah 的更具可读性。如果你有相反的感觉,那很好。在发现瓶颈后,我只会考虑不必要的“ifs”对性能的影响。
      • 另外,我的解决方案是一个更普遍适用的解决方案,因为它只依赖于能够写。您可以采用我的解决方案并将其更改为写入流等 - 之后您可能无法取回不必要的数据。我喜欢普遍适用的模式。
      【解决方案6】:

      另一种方法是将数组的长度(如果可用)存储在单独的变量中(比每次重新检查长度更有效)。然后,您可以将索引与该长度进行比较,以确定是否添加最后一个逗号。

      编辑:另一个考虑因素是权衡删除最终字符(可能导致字符串复制)与在每次迭代中检查条件的性能成本。

      【讨论】:

      • 删除最后一个字符不应导致复制字符串。 StringBuffer 的 delete/deleteCharAt 方法最终调用 System 类中相同的源和目标数组中的以下方法: System -> public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
      【解决方案7】:

      这里有一个解决方案:

      int[] array = {1, 2, 3...};
      StringBuilder builder = new StringBuilder();
      bool firstiteration=true;
      
      for(int i : array)
      {
          if(!firstiteration)
              builder.append(",");
      
          builder.append("" + i);
          firstiteration=false;
      }
      

      寻找第一次迭代 :)

      【讨论】:

        【解决方案8】:

        这里有两条替代路径:

        1:Apache Commons String Utils

        2:保留一个名为 first 的布尔值,设置为 true。在每次迭代中,如果first 为假,则附加逗号;之后,将first 设置为 false。

        【讨论】:

        • 1) 链接失效 2) 我花了更长的时间阅读描述而不是代码:)
        【解决方案9】:

        也许您在作业中使用了错误的工具。

        这比你正在做的更手动,但它在某种程度上更优雅,如果不是有点“老派”

         StringBuffer buffer = new StringBuffer();
         Iterator iter = s.iterator();
         while (iter.hasNext()) {
              buffer.append(iter.next());
              if (iter.hasNext()) {
                    buffer.append(delimiter);
              }
         }
        

        【讨论】:

          【解决方案10】:

          另一种解决方案(也许是最有效的)

              int[] array = {1, 2, 3};
              StringBuilder builder = new StringBuilder();
          
              if (array.length != 0) {
                  builder.append(array[0]);
                  for (int i = 1; i < array.length; i++ )
                  {
                      builder.append(",");
                      builder.append(array[i]);
                  }
              }
          

          【讨论】:

          • 这是一个自然的解决方案,只是它依赖于数组不为空。
          • @orcmid:如果数组是空的,那么这仍然会给出正确的输出——一个空字符串。我不确定你的意思是什么。
          【解决方案11】:

          另一种方法:

          String delim = "";
          for (int i : ints) {
              sb.append(delim).append(i);
              delim = ",";
          }
          

          更新:对于 Java 8,您现在拥有 Collectors

          【讨论】:

          • 不得不删除我的类似答案 - 这将教会我在更仔细地查看其他答案之前不要发布。
          • 另请注意,这可以处理 Robert Paulson 在另一个评论线程中提到的潜在问题 - 此技术不依赖于在附加数组值时 StringBuilder 为空。
          • 虽然代码更流畅/整洁/有趣,但不如if版本明显。始终使用更明显/可读的版本。
          • @Bill:这不是一个硬性规定;有时“聪明”的解决方案是“更正确”的解决方案。更重要的是,你真的认为这个版本很难阅读吗?无论哪种方式,维护人员都需要逐步完成 - 我认为差异并不显着。
          • 尽管您写入文件系统的写入调用等其他资源,但它仍然有效。好主意。
          【解决方案12】:

          如果您只是将数组转换为逗号分隔的数组,许多语言都有专门的连接函数。它将一个数组变成一个字符串,每个元素之间都有一个分隔符。

          【讨论】:

            【解决方案13】:

            你需要Class Separator

            Separator s = new Separator(", ");
            for(int i : array)
            {
                 builder.append(s).append(i);
            }
            

            Separator 类的实现很简单。它包装了一个字符串,该字符串在每次调用 toString() 时返回,但第一次调用除外,它返回一个空字符串。

            【讨论】:

              【解决方案14】:

              基于java.util.AbstractCollection.toString(),提前退出以避免分隔符。

              StringBuffer buffer = new StringBuffer();
              Iterator iter = s.iterator();
              for (;;) {
                buffer.append(iter.next());
                if (! iter.hasNext())
                  break;
                buffer.append(delimiter);
              }
              

              它高效而优雅,但不像其他一些答案那样不言而喻。

              【讨论】:

              • (! i.hasNext()) 时忘记包含早期返回,这是整体方法稳健性的重要组成部分。 (这里的其他解决方案可以优雅地处理空集合,所以你也应该这样做!:)
              【解决方案15】:

              另一种选择。

              StringBuilder builder = new StringBuilder();
              for(int i : array)
                  builder.append(',').append(i);
              String text = builder.toString();
              if (text.startsWith(",")) text=text.substring(1);
              

              【讨论】:

              • 我在另一个问题上做了修改
              【解决方案16】:

              这几乎是this StackOverflow question 的重复。你想要的是 StringUtils,并调用 join 方法。

              StringUtils.join(strArr, ',');
              

              【讨论】:

                【解决方案17】:

                这里描述的许多解决方案有点过头了,恕我直言,尤其是那些依赖外部库的解决方案。有一个很好的干净、清晰的习惯用法来实现我一直使用的逗号分隔列表。它依赖于条件 (?) 运算符:

                编辑:原始解决方案正确,但根据 cmets 不是最佳的。第二次尝试:

                    int[] array = {1, 2, 3};
                    StringBuilder builder = new StringBuilder();
                    for (int i = 0 ;  i < array.length; i++)
                           builder.append(i == 0 ? "" : ",").append(array[i]); 
                

                到此为止,只需 4 行代码,包括数组的声明和 StringBuilder。

                【讨论】:

                • 但是您在每次迭代时都会创建一个新的 StringBuilder(感谢 + 运算符)。
                • 是的,如果您查看字节码,您是对的。我不敢相信这么简单的问题会变得如此复杂。不知编译器能不能在这里优化。
                • 提供了第二个,希望是更好的解决方案。
                【解决方案18】:

                在这种情况下,真的不需要知道它是否是最后一次重复。 我们有很多方法可以解决这个问题。一种方法是:

                String del = null;
                for(int i : array)
                {
                    if (del != null)
                       builder.append(del);
                    else
                       del = ",";
                    builder.append(i);
                }
                

                【讨论】:

                  【解决方案19】:

                  这是我运行的 SSCCE 基准测试(与我必须实施的相关),结果如下:

                  elapsed time with checks at every iteration: 12055(ms)
                  elapsed time with deletion at the end: 11977(ms)
                  

                  至少在我的示例中,在每次迭代时跳过检查并不明显更快,尤其是对于正常的数据量,但它更快。

                  import java.util.ArrayList;
                  import java.util.List;
                  
                  
                  public class TestCommas {
                  
                    public static String GetUrlsIn(int aProjectID, List<String> aUrls, boolean aPreferChecks)
                    {
                  
                      if (aPreferChecks) {
                  
                        StringBuffer sql = new StringBuffer("select * from mytable_" + aProjectID + " WHERE hash IN ");
                  
                        StringBuffer inHashes = new StringBuffer("(");
                        StringBuffer inURLs = new StringBuffer("(");
                  
                        if (aUrls.size() > 0)
                        {
                  
                        for (String url : aUrls)
                        {
                  
                          if (inHashes.length() > 0) {
                          inHashes.append(",");
                          inURLs.append(",");
                          }
                  
                          inHashes.append(url.hashCode());
                  
                          inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"");//.append(",");
                  
                        }
                  
                        }
                  
                        inHashes.append(")");
                        inURLs.append(")");
                  
                        return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
                      }
                  
                      else {
                  
                        StringBuffer sql = new StringBuffer("select * from mytable" + aProjectID + " WHERE hash IN ");
                  
                        StringBuffer inHashes = new StringBuffer("(");
                        StringBuffer inURLs = new StringBuffer("(");
                  
                        if (aUrls.size() > 0)
                        {
                  
                        for (String url : aUrls)
                        {
                          inHashes.append(url.hashCode()).append(","); 
                  
                          inURLs.append("\"").append(url.replace("\"", "\\\"")).append("\"").append(",");
                        }
                  
                        }
                  
                        inHashes.deleteCharAt(inHashes.length()-1);
                        inURLs.deleteCharAt(inURLs.length()-1);
                  
                        inHashes.append(")");
                        inURLs.append(")");
                  
                        return sql.append(inHashes).append(" AND url IN ").append(inURLs).toString();
                      }
                  
                    }
                  
                    public static void main(String[] args) { 
                          List<String> urls = new ArrayList<String>();
                  
                      for (int i = 0; i < 10000; i++) {
                        urls.add("http://www.google.com/" + System.currentTimeMillis());
                        urls.add("http://www.yahoo.com/" + System.currentTimeMillis());
                        urls.add("http://www.bing.com/" + System.currentTimeMillis());
                      }
                  
                  
                      long startTime = System.currentTimeMillis();
                      for (int i = 0; i < 300; i++) {
                        GetUrlsIn(5, urls, true);
                      }
                      long endTime = System.currentTimeMillis();
                      System.out.println("elapsed time with checks at every iteration: " + (endTime-startTime) + "(ms)");
                  
                      startTime = System.currentTimeMillis();
                      for (int i = 0; i < 300; i++) {
                        GetUrlsIn(5, urls, false);
                      }
                      endTime = System.currentTimeMillis();
                      System.out.println("elapsed time with deletion at the end: " + (endTime-startTime) + "(ms)");
                    }
                  }
                  

                  【讨论】:

                  【解决方案20】:

                  正如工具包所述,在 Java 8 中,我们现在拥有 Collectors。代码如下所示:

                  String joined = array.stream().map(Object::toString).collect(Collectors.joining(", "));
                  

                  我认为这正是您正在寻找的,并且它是您可以用于许多其他事情的模式。

                  【讨论】:

                    【解决方案21】:

                    由于它是一个固定数组,因此更容易避免增强 for... 如果 Object 是一个集合,则迭代器会更容易。

                    int nums[] = getNumbersArray();
                    StringBuilder builder = new StringBuilder();
                    
                    // non enhanced version
                    for(int i = 0; i < nums.length; i++){
                       builder.append(nums[i]);
                       if(i < nums.length - 1){
                           builder.append(",");
                       }   
                    }
                    
                    //using iterator
                    Iterator<int> numIter = Arrays.asList(nums).iterator();
                    
                    while(numIter.hasNext()){
                       int num = numIter.next();
                       builder.append(num);
                       if(numIter.hasNext()){
                          builder.append(",");
                       }
                    }
                    

                    【讨论】:

                      【解决方案22】:

                      您可以使用StringJoiner

                      int[] array = { 1, 2, 3 };
                      StringJoiner stringJoiner = new StringJoiner(",");
                      
                      for (int i : array) {
                          stringJoiner.add(String.valueOf(i));
                      }
                      
                      System.out.println(stringJoiner);
                      

                      【讨论】:

                        猜你喜欢
                        • 2015-11-03
                        • 2011-07-11
                        • 2016-05-10
                        • 2016-08-25
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-05-17
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多