9

When I have a for loop, I use the i to refer to the elements of my array, objects, etc.

Like:
Current item: myArray[i]
Next item: myArray[i+1]
Previous item: myArray[i-1]

But at the moment, I'm using a foreach loop ( for (Object elem : col) { ).
How do I refer to the previous item?
(I need to do a search an 'array', which I'm doing with for (Object object : getComponents()).

But when it returns true (so it finds what I look for), it should perform the code on the previous and the next item.

Clarification: I have java.awt.Component elements!

Apache
  • 1,060
  • 5
  • 21
  • 38
  • (I can think about a workaround like using a temporary / disposable integers, to 'mark' these items. Like tempInt1, tempInt2. I would use an additional marker, and if it returns true, I would use these integers like: tempInt2 = mark-1 and tempInt2 = mark+1. And then just manipulate the marked ones.) – Apache Dec 19 '11 at 17:32
  • But I guess there must be a cleaner way to do this. :D – Apache Dec 19 '11 at 17:32
  • 2
    why not go for normal for loop? – Bhushan Dec 19 '11 at 17:56
  • @Bhushan - The lack of normal education... I guess? :) – Apache Dec 19 '11 at 18:08
  • 2
    The foreach-loop is practical, but quite limited. I often have to use the old for-loop. – toto2 Dec 19 '11 at 18:08
  • Found a similar question, but the solution uses the same foreach loop. http://stackoverflow.com/questions/1037139/loop-through-jpanel – Apache Dec 19 '11 at 18:13

5 Answers5

10

If the data-structure is a List, then you can use a ListIterator directly. The ListIterator is special because it contains both the methods next() and previous()

List list = ...;
ListIterator iter = list.listIterator(); //--only objects of type List has this
while(iter.hasNext()){
    next = iter.next();
    if (iter.hasPrevious()) //--note the usage of hasPrevious() method
       prev = iter.previous(); //--note the usage of previous() method
}
Suraj Chandran
  • 24,433
  • 12
  • 63
  • 94
  • 2
    Of course, it should be noted that `previous()` moves the iterator _backwards_, meaning a pair call to 'next()` and 'previous()` will cause a net effect of having the iterator stay in place. – Clockwork-Muse Dec 19 '11 at 18:01
  • Same thing, problem with the awt like objects. Should I convert them into a list, or the values into a list, change the values and then back to *objects? – Apache Dec 19 '11 at 18:23
  • @X-Zero, right, that's why I explicitly mentioned that in the code-comments, and the purpose was only to show the usage :) – Suraj Chandran Dec 19 '11 at 18:39
  • 4
    @Suraj - You don't mention that `previous()` moves the iterator **at all** (although it might be inferrable because of `next()`). All the `hasPrevious()` does is prevent exceptions from being thrown - you need another call to `next()` in there for the loop to actually advance... – Clockwork-Muse Dec 19 '11 at 19:18
  • As noted in the other comments, beware that this code will not advance the iterator, and as such will not work as the OP expected. You need another next() at the end to make it work correctly, which ends up being not a particularly clean solution. – Zelgadis Dec 20 '20 at 11:59
5

The foreach loop won't let you do that. My suggestion is to go back to using the good old fashioned Iterator. For example

final Iterator itr=getComponents().iterator();
Object previous=itr.next();
Object current=itr.next();
while(itr.hasNext()){
    Object next=itr.next();
    //Do something with previous, current, and next.
    previous=current;
    current=next;
}
Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77
  • I'll try it in 15minutes and report back. Thanks! – Apache Dec 19 '11 at 17:35
  • wouldn't the two calls to itr.next() before the while loop cause the while loop to start at the third element in the collection? – DaveH Dec 19 '11 at 17:40
  • @DaveHowes There are 3 variables : previous, current and next. – toto2 Dec 19 '11 at 18:07
  • @Jack: I have java.awt.components... and the Iterator gives me an error because of that. :-/ – Apache Dec 19 '11 at 18:09
  • @DaveHowes When the loop starts, previous is the first element, current is the second element, and next becomes the third element. I probably should have put some guards just in case the list didn't have 3 elements but I was worried that might clutter up the code and make it more difficult to understand. – Jack Edmonds Dec 29 '11 at 19:34
  • @JackEdmonds - yes - I re-read and I saw that it worked. It just feels a little counter-intuitive that the first itr.next() in the while loop doesn't retrieve the first element from the collection, and that the element that has just been read from the iterator is assigned to the "next" variable. Having said that, I can see that the code would work. – DaveH Jan 03 '12 at 22:50
3
JButton prev, next, curr;
Component[] arr = getComponents();

for(int i=1;i<arr.length-1;i++) {
    if (yourcondition == true) {
        curr = (JButton) arr[i];
        prev = (JButton) arr[i-1];
        next = (JButton) arr[i+1];
    }
}
Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141
1

I did this to access the previous and next elements in a list while using enhanced for loop.

Here's a quick snippet:

import java.util.ArrayList;
import java.util.List;

class Scratch {

  public static void main(String[] args) {
    List<Integer> myInts = new ArrayList<>();
    myInts.add(1);
    myInts.add(2);
    myInts.add(3);
    myInts.add(4);
    myInts.add(5);

    Integer next = null;
    Integer previous = null;

    for (Integer current: myInts) {
        try {
                previous = myInts.get(myInts.indexOf(current)-1);
            } catch (IndexOutOfBoundsException ignored){
               // ignored
            }
        try {
                next = myInts.get(myInts.indexOf(current)+1);
            } catch (IndexOutOfBoundsException ignored){
                next = null;
            }
        System.out.println("previous = " + previous);
        System.out.println("current = " + current);
        System.out.println("next = " + next);
    }
  }
}

Output:

previous = null
current = 1
next = 2
previous = 1
current = 2
next = 3
previous = 2
current = 3
next = 4
previous = 3
current = 4
next = 5
previous = 4
current = 5
next = null

Yeah! I know, the code's ugly. But, it get's the job done.

sgiri
  • 691
  • 12
  • 28
0

Array indexing

If you have an array-like data-structure (e.g. an actual array or something like an ArrayList), then referencing i, i-1, i+1 will give good performance so there isn't much more to it. (Although having to turn a For-Each Loop into an index counting For Loop isn't very fun and is one of the few caveats.)

The answer offered by Sergey does something like this.

The versatile ListIterator

If you can get your hands on an ListIterator (which is actually quite a big assumption), the answer offered by Suraj could suffice. But do note both next() and previous() moves the iterator position. So if you did something like the following for each loop iteration: prev = previous(); current = next(); next = next(); previous(), you'll end up performing roughly 4 iteration operations per loop. This isn't much of a problem if iteration is cheap, and luckily this is often the case for data-structures that offers a ListIterator.

Generic solution

The generic solution for any Iterable (or Iterator) should make no random lookups (as is possible with an array) or make assumptions regarding performance of next(), which should be called at most N times where N is the number of available elements.

Here's one such implementations:

final Iterator<E> it = iterable.iterator();

for (E next = (it.hasNext() ? it.next() : null), current = null; next != null;) {
    E previous = current;
    current = next;
    next = it.hasNext() ? it.next() : null;

    // Do something using 'current', 'previous' and 'next'.
    // NB: 'previous' and/or 'next' are null when 'current' is
    // the first and/or last element respectively
}

Mind, this implementation has caveats of its own:

  • It'll break if Iterable contains null elements.
  • Neither current or next are effectively-final, so cannot be used directly in them fangled Java 8 lambdas.
antak
  • 19,481
  • 9
  • 72
  • 80