4
\$\begingroup\$

This is a follow up question for this question:

Implementation of a dynamic list-like array


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 ignoresnull and returns the index of theinserted item so it can be used withget() andremove().
  • After some thought, theremove() 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 toBucketArray fromBagArray because 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    }
toto2's user avatar
toto2
5,46017 silver badges21 bronze badges
askedOct 2, 2015 at 16:14
Daniel Mendel's user avatar
\$\endgroup\$

2 Answers2

2
\$\begingroup\$

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: 3

i1.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.

answeredOct 5, 2015 at 16:20
h.j.k.'s user avatar
\$\endgroup\$
-5
\$\begingroup\$

Try usingArrayList:

import java.util.ArrayList;

It's a dynamic array and has features such as insertion, deletion, etc.

Jamal's user avatar
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
answeredOct 2, 2015 at 19:58
Mohammad Yaqoob's user avatar
\$\endgroup\$
1
  • \$\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\$CommentedOct 2, 2015 at 20:04

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.