3

I need some container to keep elements so, if I'll try to get the size()+i element, i'll get element number i. Or with iterator, which starts from the beginning of container after it tries to get the last element? What are the best practicies in both cases? I mean performance and easy useability.

Deepscorn
  • 822
  • 10
  • 22
  • 1
    I think that's called a "ring buffer", or a "circular buffer". Not sure about Java, C++ has one in Boost... – Kerrek SB Aug 26 '11 at 20:22
  • Are you sure it's a good idea to have such a data structure? What do you need it for? – toto2 Aug 26 '11 at 21:25
  • I have a DodgerAI class, which handles AI for some hero in game. It has a field - index of hero and field, representing game logic. There are many situations in AI (method in DodgerAI), when all heros, except hero, controlled by AI, must be analyzed. Thats why I want to use some kind of "ring". – Deepscorn Aug 27 '11 at 17:20

4 Answers4

9

You could create a simple subclass of ArrayList<T> and override the get(int n) method as follows:

public T get(int n)
{
    return super.get(n % this.size());
}

As to the iterator, you will need to implement your own, which shouldn't be all that hard.

EDIT:

Assuming your new class is called RingList, here's a sample RingIterator (untested):

public class RingIterator<T> implements Iterator<T>
{
    private int cur = 0;
    private RingList<T> coll = null;

    protected RingIterator(RingList<T> coll) { this.coll = coll; }
    public boolean hasNext() { return size() > 0; }
    public T next() 
    { 
        if (!hasNext()) 
            throw new NoSuchElementException();
        int i=cur++; 
        cur=cur%size(); 
        return coll.get(i);
    }
    public void remove() { throw new UnsupportedOperationException(); }
}

You would then override the iterator() method in RingList<T> as

public Iterator<T> iterator()
{
    return new RingIterator(this);
}
Jim Garrison
  • 85,615
  • 20
  • 155
  • 190
2

For the first part, just ask for n % list.size() perhaps?

For the iterator part, create a class that wraps an iterator, and when next() returns null, just have it reset the iterator.

Marvo
  • 17,845
  • 8
  • 50
  • 74
1

Thanks everyone, thats what I've created:

public class RingIterator<E> {
private List<E> _lst;
private ListIterator<E> _lstIter;

public RingIterator(ListIterator<E> iter, List<E> lst) {
    super();
    _lstIter = iter;
    _lst = lst;
}

public E next() {
    if(!_lstIter.hasNext())
        _lstIter = _lst.listIterator();
    return _lstIter.next();
}

public E previous() {
    if(!_lstIter.hasPrevious())
        _lstIter = _lst.listIterator(_lst.size());
    return _lstIter.previous();
}

}

Then get method:

/*
 * Returns ring iterator,
 * use it with 'ParentClass' type.
 */
public RingIterator<SubClass> getRingIter(int i) {
    return new RingIterator(_subs.listIterator(i),_subs);
}

And I use it:

RingIterator<SubClass> ri = _logic.getRingIter(1);
ParentClass ai = ri.next();

I wanted to make only type ParentClass (not SubClass) available via getRingIter, but I don't see a way to do it with no creation of List - convertion of List.

Deepscorn
  • 822
  • 10
  • 22
0

Extend the ArrayList class and implement the get(Integer) method the way you like. I think this is the 'best practice'.

Pedro Montoto García
  • 1,672
  • 2
  • 18
  • 38