2

EDIT 3: this is the cause of the problem:

For removeArrayElement (first version), its returning toArray(new Item[0]), which executes the null element at the end, but with the new method, it returns toArray(arr), which does not execute the null, but you can;t create a generic type array of T, i.e new T[0], so what is a substitute? instead of 'passing the array again' to get rid of the null element at the end

Old problem:

I recently updated how I was handling array sorting by creating one master method (by implements generic types) Only the aftermath method is giving me array out of bounds errors.

Is there anything I've missed?

Old methods:

private static Item[] insertTabItem(Item[] a, int pos, Item item) {
    Item[] result = new Item[a.length + 1];
    for(int i = 0; i < pos; i++)
        result[i] = a[i];
    result[pos] = item;
    for(int i = pos + 1; i < a.length + 1; i++)
        result[i] = a[i - 1];
    return result;
}

private static Item[] removeArrayItem(Item[] arr, Item item) {
   List<Item> list = new ArrayList<Item>(Arrays.asList(arr));
      for (int i = 0; i < list.size(); i++) {
          if (list.get(i) == item) {
              list.remove(i);
          }
      }
     return list.toArray(new Item[0]);
}

new methods (giving java.lang.ArrayIndexOutOfBoundsException)

public static <T> T[] insertArrayElement(T[] arr, int pos, T item) {
     final int N = arr.length;
    T[] result = Arrays.copyOf(arr, N + 1);
    for(int i = 0; i < pos; i++)
        result[i] = arr[i];
    result[pos] = item;
    for(int i = pos + 1; i < N + 1; i++)
        result[i] = arr[i - 1];
    return result;
}

public static <T> T[] removeArrayElement(T[] arr, T item) {
   List<T> list = new ArrayList<T>(Arrays.asList(arr));
      for (int i = 0; i < list.size(); i++) {
          if (list.get(i) == item) {
              list.remove(i);
          }
      }
     return list.toArray(arr);
}

EDIT:

After reading through some of the answer I've changed the removeArrayElement to this:

public static <T> T[] removeArrayElement(T[] arr, T item) {
   for (Iterator<T> iterator = list.iterator(); iterator.hasNext();) {
       T t = iterator.next();
        if (t == item) {
            iterator.remove();
        }
    }
     return list.toArray(arr);
}

but it still for some reason sends this: java.lang.ArrayIndexOutOfBoundsException

EDIT2: Full executable

bankContents[bankSlots[0]] = Utils.removeArrayElement(bankContents[bankSlots[0]], newbankVarient);

When newBankVarient is = bankContents[bankSlots[0]][1] and removing it, System out of array AFTER is:

"[var, var, var, null]
Jack Smith
  • 43
  • 1
  • 7
  • 5
    dont use `list.remove(i)` inside a for loop. – vikingsteve Feb 16 '17 at 13:20
  • It was used in the old method too, but for some reason the new method messes up, why is that, btw its removing'i' the subject of the loop, its not removing the same element again and again – Jack Smith Feb 16 '17 at 13:22
  • To elaborate on what @vikingsteve is saying; you can another integer list that will store the values of `i` for which `list.get(i) == item` is true then iterator on the new list and remove all `i`'s in list – Laazo Feb 16 '17 at 13:24
  • http://stackoverflow.com/questions/223918/iterating-through-a-collection-avoiding-concurrentmodificationexception-when-re – RamPrakash Feb 16 '17 at 13:24
  • Show the full stack trace, as well as your testing code please. – Jorn Vernee Feb 16 '17 at 13:28
  • @Jack Smith post your input when the exception show up, – nail fei Feb 16 '17 at 13:39

4 Answers4

1

Without running your code it seems likely that removeArrayElement is causing the exception.

It's bad practise to use list.remove(i) from within a for loop that iterates the same loop.

Either, you need to break; directly after the remove(i) call, or you can consider using an iterator instead, which is "safe to delete whilst iterating".

For example: Java, Using Iterator to search an ArrayList and delete matching objects

Lastly if T is comparable then you should be able to delete from a list via list.remove(item) - you don't need to mess around with indexes if you dont need to.

Community
  • 1
  • 1
vikingsteve
  • 38,481
  • 23
  • 112
  • 156
0

as @vikingsteve has mentioned don't use remove method inside a loop, as you're most likely to jump ahead of the possible indexes.

however, you can keep the loop and start looping from the back rather than from the front.

something like this would do:

public static <T> T[] removeArrayElement(T[] arr, T item) {
   List<T> list = new ArrayList<T>(Arrays.asList(arr));
      for (int i = list.size()-1; i >= 0; i--) {
          if (list.get(i) == item) {
              list.remove(i);
          }
      }
     return list.toArray(arr);
}
Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
  • That method is still giving java.lang.ArrayIndexOutOfBoundsException – Jack Smith Feb 16 '17 at 13:34
  • Give me a second, I'll check that with debugger – Ousmane D. Feb 16 '17 at 13:36
  • This particular method for some reason doesnt remove the element but makes the element = null, which then causes array out of bounds because at the same time, externally i am minusing the variable that edits the master array size – Jack Smith Feb 16 '17 at 13:39
  • can you provide me the arguments you're passing into the methods, the full code if possible please – Ousmane D. Feb 16 '17 at 13:40
  • The method correctly sorts the array but doesnt -1 the size, therefore the final element is = null, causing the array out of bounds – Jack Smith Feb 16 '17 at 13:47
  • is that using the solution i have provided ? – Ousmane D. Feb 16 '17 at 13:50
  • Yes, as a quickfix: T[] newArr = Arrays.copyOf(arr, arr.length - 1);, would suffice, any ideas for a more efficient method? – Jack Smith Feb 16 '17 at 13:52
  • For removeArrayElement (first version), its returning toArray(new Item[0]), which executes the null element at the end, but with the new method, it returns toArray(arr), which does not execute the null, but you can;t create a generic type array of T, i.e new T[0], so what is a substitute? instead of 'passing the array again' to get rid of the null element at the end – Jack Smith Feb 16 '17 at 14:03
0

remove inside a loop is the problem.eitger decrement i by 1 (i --) when an item is removed or use iterator based loop and call iterator.remove

ABHIJITH GM
  • 134
  • 4
0

For your EDIT 3, it's the correct behaviour described in the javadoc

If the list fits in the specified array with room to spare (i.e., the array has more elements than the list), the element in the array immediately following the end of the list is set to null. (This is useful in determining the length of the list only if the caller knows that the list does not contain any null elements.)

Keep the type with an empty copy of your array

private static Item[] removeArrayItem(Item[] arr, Item item) {
    Item[] emptyArray = Arrays.copyOf(arr, 0);
    List<Item> list = new ArrayList<Item>(Arrays.asList(arr));
    for (Iterator<Item> iter = list.iterator(); iter.hasNext();) {
      Item current = iter.next();
      if (item.equals(current)) {
        iter.remove();
        break;
      }
    }
    return list.toArray(emptyArray);
}

Btw, equality test on ref is a bad pratice, prefer the equals when you can. Maybe you can also, if your items are comparable, use the Arrays.binarySearch to get the index of the item you want to remove avoiding iterator in favor of a direct use remove(index) on the list.