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));
}
4

5 回答 5

7

您需要使用受限于数组大小的索引。更准确地说,更深奥地说,您需要将 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 循环迭代)到范围(有效数组索引)的函数映射。

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

于 2013-09-10T18:04:12.540 回答
7

虽然luis.espinal的答案在性能方面更好,但我认为您还应该查看Iterator 的答案,因为它们将为您提供更大的来回阅读灵活性。

这意味着您可以FLAMESFLAMESFLAMESSEMALF, 等一样简单地编写...

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();
}
于 2013-09-10T18:16:59.570 回答
5

您应该使用%强制索引停留在flames.length其中,以便它们生成有效索引

int len = flames.length;
for(int z = 0; z < ctr-1; z++){
      res = (flames[z % len]);
      jLabel1.setText(String.valueOf(res));
}
于 2013-09-10T17:37:58.220 回答
2

您可以尝试以下方法:-

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));
}
于 2013-09-10T17:37:58.513 回答
1

这是我将如何做到这一点:

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

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

文本循环方法:

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需要在循环外初始化)。现在已经修好了。我还将它重构为一个单独的函数。

于 2013-09-10T20:13:45.237 回答