关于java:在到达数组中的最后一个索引后返回第一个索引

Going back to the first index after reaching the last one in an array

在for循环中的数组到达最后一个索引后,我得到一个异常,说明该索引超出了界限。我想让它回到第一个指数,直到z等于ctr。我该怎么做?

我的代码:

1
2
3
4
5
6
7
8
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));
}


虽然luis.espinal的答案在性能方面更好,但我认为您还应该研究一下迭代器,因为它们将为您提供更大的前后阅读灵活性。

也就是说,你可以和FLAMESSEMALF一样轻松地写FLAMESFLAMES等。

1
2
3
4
5
6
7
8
9
10
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
}

出于好奇,做这个循环1百万次(100个样本的平均结果)需要:

1
2
3
               using modulo: 51ms
            using iterators: 95ms
using guava cycle iterators: 453ms

编辑:正如lbalazcs所说,循环迭代器甚至更加优雅。它们是有代价的,而guava的实现速度慢了4倍。你可以自己动手,很难。

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


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

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


您需要使用一个受数组大小限制的索引。更准确、更深奥地说,您需要将for-loop迭代0..9映射到火焰数组0..flames.length()-1的有效索引,在本例中,这与0..5_相同。

当循环从0迭代到5时,映射很简单。当循环第6次迭代时,需要将其映射回数组索引0,当循环第7次迭代时,需要将其映射到数组索引1,依此类推。

= NA?ve路==

1
2
3
4
5
6
7
8
9
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循环。

1
2
3
4
5
6
7
8
9
10
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));
}

==如何操作==

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

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

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

更重要的是,在你开始编码之前,先把它写在纸上。这将需要你很长的时间来解决这些基本问题。


您可以尝试以下操作:

1
2
3
4
5
6
7
8
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));
}


我可以这样做:

1
2
3
4
String flames ="FLAMES";
int ctr = 10;

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

textLoop方法:

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