【问题标题】:Going back to the first index after reaching the last one in an array到达数组中的最后一个索引后返回第一个索引
【发布时间】:2013-09-14 13:08:11
【问题描述】:

在 for 循环中的数组到达最后一个索引后,我收到一个异常,指出索引超出范围。我想要的是让它回到第一个索引,直到z 等于ctr。我该怎么做?

我的代码:

char res;
int ctr = 10
char[] flames = {'F','L','A','M','E','S'};

for(int z = 0; z < ctr-1; z++){
    res = (flames[z]);
    jLabel1.setText(String.valueOf(res));
}

【问题讨论】:

  • 在访问flames[] 时使用% 就像...flames[z%flames.length()];
  • 在索引表达式上使用 mod (%) 运算符:res = flames[z % flames.length()]; 或者更好的是,在 for 循环之外有一个 invariant 变量 n = flames.length(),并且然后有res = flames[z % n];
  • @luis.espinal :编译器不会为我们做这件事吗?循环中的flames.length() 会被编译器优化,不是吗?
  • @boxed__l - 好问题。我不相信它会做 IIRC。确认这一点的一种方法是在两个版本上使用 javap 反汇编程序(有和没有循环外的不变量)并比较两者的输出。
  • @luis.espinal :看来你是对的。在类似的代码上进行了反汇编。没有优化。有像ProGuard 这样的项目可以进行这种优化等等。 +1

标签: java arrays


【解决方案1】:

我会这样做:

String flames = "FLAMES";
int ctr = 10;

textLoop(flames.toCharArray(), jLabel1, ctr);

textLoop 方法:

void textLoop(Iterable<Character> text, JLabel jLabel, int count){
    int idx = 0;
    while(true)
        for(char ch: text){
            jLabel.setText(String.valueOf(ch));
            if(++idx < count) return;
        }
}

编辑:在代码中发现了一个错误(idx 需要在循环外初始化)。现在已经修好了。我还将它重构为一个单独的函数。

【讨论】:

    【解决方案2】:

    虽然luis.espinal 的答案在性能方面更好,但我认为您还应该看看Iterator's,因为它们可以让您更灵活地来回阅读。 p>

    意思是你可以像FLAMESSEMALF 一样简单地写FLAMESFLAMES 等等......

    int ctr = 10;
    List<Character> flames = Arrays.asList('F','L','A','M','E','S');
    Iterator it = flames.iterator();
    
    for(int z=0; z<ctr-1; z++) {
        if(!it.hasNext()) // if you are at the end of the list reset iterator
            it = flames.iterator();
    
        System.out.println(it.next().toString()); // use the element
    }
    

    出于好奇,执行此循环 1M 次(100 个样本的平均结果)需要:

                   using modulo: 51ms
                using iterators: 95ms
    using guava cycle iterators: 453ms
    

    编辑: 循环迭代器,正如lbalazscs 所说,更加优雅。它们是有代价的,而 Guava 的实现速度要慢 4 倍。你可以推出自己的实现,很难。

    // guava example of cycle iterators
    Iterator<Character> iterator = Iterators.cycle(flames);
    for (int z = 0; z < ctr - 1; z++) {
        res = iterator.next();
    }
    

    【讨论】:

    【解决方案3】:

    您应该使用% 强制索引保持在flames.length 内,以便它们生成有效索引

    int len = flames.length;
    for(int z = 0; z < ctr-1; z++){
          res = (flames[z % len]);
          jLabel1.setText(String.valueOf(res));
    }
    

    【讨论】:

    • flames.length() 移出 for 循环。它是一个不变量。
    【解决方案4】:

    您需要使用限制为数组大小的索引。更准确地说,您需要将 for 循环迭代 {0..9} 映射到火焰数组 {0..flames.length()-1} 的有效索引,在这种情况下,它们与 { 0..5}.

    当循环从 0 迭代到 5 时,映射是微不足道的。当循环第 6 次迭代时,你需要将它映射回数组索引 0,当它迭代到第 7 次时,你将它映射到数组索引 1,以此类推。

    == 天真的方式 ==

    for(int z = 0, j = 0; z < ctr-1; z++, j++)
    {
          if ( j >= flames.length() )
          {
             j = 0; // reset back to the beginning
          }
          res = (flames[j]);
          jLabel1.setText(String.valueOf(res));
    }
    

    == 更合适的方式 ==

    然后你可以通过实现flames.length() 是一个不变量来改进它,你可以将它移出for循环。

    final int n = flames.length();
    for(int z = 0, j = 0; z < ctr-1; z++, j++)
    {
          if ( j >= n )
          {
             j = 0; // reset back to the beginning
          }
          res = (flames[j]);
          jLabel1.setText(String.valueOf(res));
    }
    

    == 怎么做 ==

    现在,如果您注意的话,您会看到我们只是对索引进行模运算。因此,如果我们使用模块化 (%) 运算符,我们可以简化您的代码:

    final int n = flames.length();
    for(int z = 0; z < ctr-1; z++)
    {
          res = (flames[z % n]);
          jLabel1.setText(String.valueOf(res));
    }
    

    在处理此类问题时,请考虑从域(在本例中为 for 循环迭代)到范围(有效数组索引)的函数映射。

    更重要的是,在开始编写代码之前就将其写在纸上。这将使您在解决这些类型的基本问题方面走得很远。

    【讨论】:

      【解决方案5】:

      您可以尝试以下方法:-

      char res;
      int ctr = 10
      char[] flames = {'F','L','A','M','E','S'};
      int n = flames.length();
      for(int z = 0; z < ctr-1; z++){
          res = flames[z %n];
          jLabel1.setText(String.valueOf(res));
      }
      

      【讨论】:

      • flames.length() 移出 for 循环。它是一个不变量。
      • @luis.espinal:- 喜欢你的第二个想法。在我的回答中添加了这个!!谢谢
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-14
      • 1970-01-01
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 2017-05-29
      相关资源
      最近更新 更多