2013-09-10 5 views
8

После того, как мой массив в цикле 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)); 
} 
+0

использовать '%' при доступе к 'flames []' like ... 'flames [z% flames.length()];' –

+0

использовать оператор mod (%) в выражении индекса: 'res = flames [z % flames.length()]; 'Или еще лучше иметь переменную * инварианта * n = flames.length()' непосредственно за пределами цикла for, а затем иметь 'res = flames [z% n];' –

+2

@ luis.espinal: Разве компилятор не сделает это для нас? 'flames.length()' в цикле будет оптимизирован правым компилятором/не так ли? –

ответ

4

Вам нужно использовать индекс, который ограничен размером массива. Точнее, и эзотерически, вам нужно сопоставить итерации for-loop {0..9} с действительными индексами для массива пламени {0 .. flames.length()-1}, которые в этом случае совпадают с {0. 0,5}.

Когда цикл повторяется от 0 до 5, отображение тривиально. Когда цикл повторяется в 6-й раз, вам нужно сопоставить его обратно с индексом массива 0, когда он итерации до седьмого раза, вы сопоставляете его с индексом массива 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() является инвариантом, который вы двигаетесь из за петлю ,

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

При работе с проблемами, как это, думать о функциональных отображениях из домена (в данном случае, для итераций цикла) для Диапазон (действительные индексы массива).

Что еще более важно, проработайте его на бумаге, прежде чем вы даже начнете код. Это займёт вам долгий путь к решению этих типов элементарных проблем.

5

Вы должны использовать %, чтобы заставить индекс пребывания в flames.length так, что они делают правильный индекс

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

переместите 'flames.length()' из цикла for. Это инвариант. –

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)); 
} 
+0

переместите 'flames.length()' из цикла for. Это инвариант. –

+1

@ luis.espinal: - Понравилась вторая идея. Добавлено в мой ответ !! спасибо –

6

Хотя luis.espinal ответ с точки зрения производительности, лучше я думаю вы также должны взглянуть в Iterator's, как они дадут вам большую гибкость чтения назад и вперед.

Значит, вы могли бы так же просто написать FLAMESFLAMES как FLAMESSEMALF и т. Д.

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 

Edit: цикл итераторы, а 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(); 
} 
+0

Еще более элегантно использовать бесконечные/циклические итераторы, например: http://stackoverflow.com/questions/2622591/is-an-infinite-iterator-bad-design – lbalazscs

+0

@lbalazscs благодарит за комментарий. Произошло некоторое тестирование и обновлено соответствующим образом. – Frankie

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

EDIT: нашел ошибку в коде (idx необходимое для инициализации вне цикла). Теперь это исправлено. Я также реорганизовал его в отдельную функцию.

Смежные вопросы