This is a follow up question for this question:
This is an implementation of an array that behaves like a list, granting me an easy and quick way to:
- quickly add items
- iterate over them without caring for empty spots in the array
- quickly remove iterated items
After following userrolfl answer I revised my class to this
import java.lang.reflect.Array;import java.util.Iterator;import java.util.stream.IntStream;public class BucketArray<T> implements Iterable<T> { private final T[] mItems; private final int[] mSlots; private int mSlotsTop = -1; public final int size; private int mIteratedIndex = -1; @SuppressWarnings("unchecked") public BucketArray(Class<T> cast, int size) { this.size = size; mItems = (T[]) Array.newInstance(cast, size); mSlots = IntStream.range(0, size).toArray(); mSlotsTop = size - 1; } public int add(T item) { if (item == null) return -1; if (mSlotsTop < 0) return -1; final int slot = popSlot(); mItems[slot] = item; return slot; } public void addAll(T... items) { for (T item : items) add(item); } public T get(int i) { if (i < 0 || i >= size) throw new IndexOutOfBoundsException(); return mItems[i]; } public int getIteratedIndex() { return mIteratedIndex; } public boolean remove(int i) { if (i < 0 || i > size) return false; if (mItems[i] == null) return false; mItems[i] = null; pushSlot(i); return true; } public void remove(T item) { remove(indexOf(item)); } public boolean removeIterated() { return remove(mIteratedIndex); } public boolean isFull() { return mSlotsTop == -1; } public boolean isEmpty() { return mSlotsTop == size - 1; } public int numFreeSlots() { return mSlotsTop + 1; } public int indexOf(T item) { for (int i = 0; i < size; i++) if (item == mItems[i]) return i; return -1; } private int popSlot() { return mSlots[mSlotsTop--]; } private void pushSlot(int s) { mSlots[++mSlotsTop] = s; } @Override public Iterator<T> iterator() { return new Iterator<T>() { private int index = -1; { if (mIteratedIndex != -1) index = mIteratedIndex; } @Override public boolean hasNext() { do { index++; if (index >= size) { mIteratedIndex = -1; return false; } } while (mItems[index] == null); return true; } @Override public T next() { mIteratedIndex = index; return mItems[index]; } }; }}Major changes:
add()method now ignoresnulland returns the index of theinserted item so it can be used withget()andremove().- After some thought, the
remove()method mostly used in the context of an iteration, so I addedremoveIterated()method that removes the currently iterated item in the scope of an iteration being made. - Name of the class changed to
BucketArrayfromBagArraybecause it sounds better.
Usage example in deleting duplicated integer values:
public static void main(String[] args) { BucketArray<Integer> mBucket = new BucketArray<Integer>(Integer.class,20); mBucket.addAll(10, 20, 30, 20, 20, 30, 10, 40); // bucket is: 40, 10, 30, 20, 20, 30, 20, 10 for (int a : mBucket) for (int b : mBucket) if (a == b) mBucket.removeIterated(); // bucket is now: 40, 10, 30, 20 }2 Answers2
Potential bug #1
The problem of using a class variablemIteratedIndex thatis modifiable in every newIterator instance created is simply, multiple such instances cannot iterate through the contentsreliably.
Potential bug #2
This is also related toIterator in thehasNext() method: calling it twice without anext() effectively skips one element. Usually, the iteration state should not be modified when doing ahasNext(), but you have aindex++ inside it.
Potential bug #3
The other problem with havingindex++ inside thehasNext() is that callers cannot reliably retrieve thenext() element without callinghasNext() first.
Illustrating all bugs
public static void main(String[] args) { BucketArray<String> instance = new BucketArray<>(String.class, 3); instance.addAll("first", "middle", "last"); Iterator<String> i1 = instance.iterator(); i1.hasNext(); i1.hasNext(); System.out.println(i1.next()); Iterator<String> i2 = instance.iterator(); i2.hasNext(); System.out.println(i2.next()); System.out.println(i2.next()); i2.hasNext(); System.out.println(i2.next());}Output:
middlefirstfirstException in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3i1.hasNext() has to be called beforei1.next(), else there will be anArrayIndexOutOfBoundsException: -1 error. Wheni1.hasNext() is called twice in succession,"middle" is returned from callingi1.next(), skipping the first element.
When we have a newi2Iterator, it starts from wherei1 left off, which bizarrely returns"first" since that was stored as the final element of the internal array - is this expected? Regardless, callingi2.next() twice returns the same value, when it shouldn't. Finally, calling the pair ofhasNext()/next() methods triggers theArrayIndexOutOfBoundsException: 3 error asi2 would have iterated past the contents of the array.
Try usingArrayList:
import java.util.ArrayList;It's a dynamic array and has features such as insertion, deletion, etc.
- \$\begingroup\$Welcome to Code Review! Please add more context to you question: how could the OP use this? What is this replacing? Why should the use this? Why is this better than what the OP already has?\$\endgroup\$SirPython– SirPython2015-10-02 20:04:10 +00:00CommentedOct 2, 2015 at 20:04
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
