Remove all occurrencies of the first element in ArrayList - java

I want to remove all elements in ArrayList that are duplicates of the first element, but I want the firs element to remain in the ArrayList. I tried to do that with for loop, but it didn't remove all duplicates.
for(int i = 1; i < arraylist.size(); i++) {
if(arraylist.get(i) == v1)
arraylist.remove(i);
}
v1 is equal to the first element of the arraylist.
I also tried with ListIterator, but it removed the first element
ListIterator<Integer> iterator = arraylist.listIterator();
while(iterator.hasNext()) {
if(iterator.next().intValue() == v1)
iterator.remove();
}
Can you please help me?

You need to read the first element separately, outside the while loop, and store it in some variable, with which you would compare the rest of the elements, to remove:
ListIterator<Integer> iterator = arraylist.listIterator();
int first = 0;
// Check if there is a first element
if (iterator.hasNext()) {
first = iterator.next();
// Iterate over the rest of the elements
while(iterator.hasNext()) {
// If this value is equal to `first`, remove it
if(iterator.next().intValue() == first) {
iterator.remove();
}
}
}
System.out.println(arrayList);
iterator.next() will return a value of type Integer. Using intValue() will give your primitive value out.
But since I'm doing the comparison with an int primitive itself, you won't need to call intValue() at all. Your Integer will automatically be unboxed to primitive int before comparison. So, replacing the if statement in while with the below one will also work:
if(iterator.next() == first) {
iterator.remove();
}
As far as your first way is concerned, I would say, always use Iterator if you want to modify the List you are looping upon. This will prevent you from facing awkward ConcurrentModificationException.
See also:
Iterating through a Collection, avoiding ConcurrentModificationException when removing in loop

You are doing the correct way by using Iterator and its method remove. But you should add a call to next() before the loop itself, in order to go over the first element and not remove it.
ListIterator<Integer> iterator = arraylist.listIterator();
iterator.next(); // pass the first element.
while(iterator.hasNext()) {
if(iterator.next().intValue() == v1)
iterator.remove();
}
Contrary to what others have said, you don't have to use "equals" if v1 is an int, which seems to be the case.

Count down (not up):
Object v1 = arraylist.get(0);
for (int i = arraylist.size() - 1; i > 1; i--) {
if (arraylist.get(i).equals(v1))
arraylist.remove(i);
}
You have to count down because as you remove elements, they the remaining ones shuffled down.
Also, you should change == to .equals() (as shown).

int v1 = arraylist.get(0);
for(int i = 0; i < arraylist.size(); i++) {
if(arraylist.get(i) == v1){
arraylist.remove(i);
i--;
}
}
If you don't want to use the Iterator approach: The other answers are correct in that you need to index from zero (if you want to remove the first one as well), but you also need to decrement your iteration variable (the i-- line) each time you remove an element from the list, because you're changing the list's length with remove().

It's best to be careful about removing elements from an array (or an iterable list) whilst iterating over it.
Easiest approach, in my experience, is to create a new list. Can you consider doing that?
Looking at your code, firstly remember to use "equals" over "==" for comparison (since .equals means "meaningfully equivalent", which I think is what you need here). (edit: may not matter here due to autoboxing, but it's still a nice habit to have)
But even this won't work:
for (int i = 1; i < arraylist.size(); i++) {
if (arraylist.get(i).equals(v1))
arraylist.remove(i);
}
Since imagine you have an ArrayList of three integers, all the same. When i == 1, The element at index 1 is compared to the value at index 0, and removed. But then the element at index 2 becomes the element at index 1, the for-loop counter is incremented, thereby "missing" to remove the last entry in the list.
Can I recommend something like this?
List<Integer> newlist = new ArrayList<Integer>();
newlist.add(v1);
for (Integer integer : arraylist) {
if (!integer.equals(v1))
newlist.add(integer);
}
Best of luck!
P.S. if you're feeling brave, you might be able to do a neat one-liner out of this:
CollectionUtils.filter(Collection,Predicate)
CollectionUtils.filter(arraylist.subList(1, arraylist.size()), new Predicate() {
#Override
public boolean evaluate(Object o) {
return !v1.equals(o);
}
});

Related

Removing element from list in counted loop vs iterator [duplicate]

This question already has answers here:
Why iterator.remove does not throw ConcurrentModificationException
(6 answers)
Closed 7 years ago.
Why is this legal:
for(int i=0; i < arr.size(); i++) {
arr.remove(i);
}
But using an iterator or the syntactic sugar of a for each results in a ConcurrentModificationException:
for(String myString : arr) {
arr.remove(myString);
}
Before everyone starts jumping on the bandwagon telling me to use iterator.remove(); I'm asking why the different behavior, not how to avoid the conc mod exception. Thanks.
Let's take a look at how, e.g., ArrayLists's iterator is implemented:
private class Itr implements Iterator<E> {
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
public E next() {
checkForComodification();
int i = cursor;
if (i >= size) throw new NoSuchElementException();
// ...
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
// ...
ArrayList.this.remove(lastRet);
// ...
cursor = lastRet;
lastRet = -1;
}
Let's look at an example:
List list = new ArrayList(Arrays.asList(1, 2, 3, 4));
Iterator it = list.iterator();
Integer item = it.next();
We remove the first element
list.remove(0);
If we want to call it.remove() now, the iterator would remove number 2 because that's what field lastRet points to now.
if (item == 1) {
it.remove(); // list contains 3, 4
}
This would be incorrect behavior! The contract of the iterator states that remove() deletes the last element returned by next() but it couldn't hold its contract in the presence of concurrent modifications. Therefore it chooses to be on the safe side and throw an exception.
The situation may be even more complex for other collections. If you modify a HashMap, it may grow or shrink as needed. At that time, elements would fall to different buckets and an iterator keeping pointer to a bucket before rehashing would be completely lost.
Notice that iterator.remove() doesn't throw an exception by itself because it is able to update both the internal state of itself and the collection. Calling remove() on two iterators of the same instance collection would throw, however, because it would leave one of the iterators in an inconsistent state.
Looking at your code, I am assuming arr is a List. In the top loop you operate on the list directly, and "re-calibrate" your condition at the top when you check
i < arr.size()
So if you remove an element, i has to compare to a lesser value.
On the other hand, in the second case you operate on the collection after an iterator has been instantiated, and don't really re-calibrate yourself.
Hope this helps.
In the first one you are modifying an array that it's not being used as an iterator on your for loop.
In the second one you are trying to access to an array that it's being modified at the same time you are iterating with it on the loop. It's why it throws ConcurrentModificationException.

How to determine last element when using an iterator?

I love to use a for loop with the iterator principle, like
for(String s : collectionWithStrings)
System.out.println(s + ", ");
Question: How can I determine if the current element is the last one?
With an own index like int = 0; i < collection.size(); i++ this is possible with i == collection.size() - 1, but not nice. Is it also possible to determine the last element with an iterator for the example above?
Indeed, the Iterator#hasNext method returns a boolean determining if the iterator will return another element with the next method.
Your iteration can be put as this:
Iterator<String> iterator = collectionWithString.iterator();
while(iterator.hasNext()) {
String current = iterator.next();
// if you invoke iterator.hasNext() again you can know if there is a next element
}
Just use the hasNext method.
if(!iterator.hasNext()) {
// this is the last element
}
Normally, we iterate using an Iterator as so:
while(iterator.hasNext()) {
Object obj = iterator.next();
}
It's not possible with an enhanced for loop without maintaining your own counter. To be honest, this is my one deciding factor when I choose which type of for loop to use.
When using an Iterator, one has access to the hasNext() method which will return false when you are processing the last element.

Why does calling remove() on an iterator give a ConcurrentModificationException?

I am trying to write a very simple method to remove duplicates in a LinkedList:
I try to do this without using additional buffer, so I maintain two iterators on the linked list, one does the normal iteration, and another iterates through all prior nodes to check for dupes (as indicated in CareerCup); however, the compiler tells me there is a CME even though I am calling itr1.remove():
public static void RemoveWithoutBuffer(LinkedList l) {
ListIterator itr1 = l.listIterator();
int count1 = 0;
int count2 = 0;
while (itr1.hasNext()) {
Object next = itr1.next();
count1++;
count2 = 0;
ListIterator itr2 = l.listIterator();
while (itr2.hasNext()) {
count2++;
if (count2 == count1)
break;
if (itr2.next() == next){
itr1.remove();
}
}
}
}
Another simpler solution of this problem with the aid of hashset is easy as follows, and no exception reported:
public static void Remove(LinkedList l) {
HashSet set = new HashSet();
ListIterator itr = l.listIterator();
while (itr.hasNext()) {
Object next = itr.next();
if (set.contains(next))
itr.remove();
else
set.add(next);
}
}
Is it because when I am iterating through itr2 I cannot modify on itr1? Is there a way to fix this? Thank you guys.
In the first case yes - you're altering the collection's contents via iterator2, while iterator1 is not aware about the changes. In the second case HashSet/HashMap don't allow removing elements while iterating through them.
You can add removed elements to another collection, and removeAll them after an iteration. E.g.
List toRemove = new ArrayList();
for (Object next : collection) {
if (someCondition) toRemove.add(next);
}
collection.removeAll(toRemove);
I hope it helps.
P.S. more details on how to remove elements from list, concerning algorithm complexity you can read here Removing ArrayList object issue
From the API docs:
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
Iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
You are getting CME because the list is modified by second iterator and first iterator is not aware of that change. When next time it tries to access the list, it is already modified. And hence it throws the exception.
Please use only one iterator to modify list at a time.
Yes. You can think of it this way: when you create an iterator it gets the list's current "modification count". When an iterator removes an element from the list, it checks the modification count to see if it is what it expects, and if all is okay, it removes the element and updates the modification count on both the iterator and the list. The other iterator will still have the old modification count and see the new value and throw the CME.
The hashset based way is the right solution in most cases. It will perform much better--two O(n) passes is usually better than O(n^2) as the nested iteration solution would produce (if it worked).
The reason why you get CME was explained by others, here is possible way you can use to remove dups
Use a List toRemove to record element at the first time iterator stumble into it, afterwards when meet again with the recorded element, remove it using iterator.remove()
private void removeDups(List list) {
List toRemove = new ArrayList();
for(Iterator it = list.iterator(); it.hasNext();) {
Object next = it.next();
if(!toRemove.contains(next)) {
toRemove.add(next);
} else {
it.remove();
}
}
toremove.clear();
}
Yes, you can fix this without using extra space.
The problem comes from executing these two lines, one after another.
itr1.remove();
itr2.hasNext();
You can use two iterators over the same list at the same time. If you are careful.
But once one of those iterators has modified the list (as it happens with itr1.remove() ) you can no longer use the other iterator (so you can't call itr2.hasNext()).
The solution is to put a break after itr1.remove(). And to update count1 :
public static void RemoveWithoutBuffer(LinkedList l) {
ListIterator itr1 = l.listIterator();
int count1 = 0;
int count2 = 0;
while (itr1.hasNext()) {
Object next = itr1.next();
count1++;
count2 = 0;
ListIterator itr2 = l.listIterator();
while (itr2.hasNext()) {
count2++;
if (count2 == count1)
break;
if (itr2.next() == next){
itr1.remove();
--count1;
break;
}
}
}
}
A more elegant solution would be to compare with elements after the current one rather than elements before the current one :
public static void RemoveWithoutBuffer(LinkedList l) {
ListIterator itr1 = l.listIterator();
while (itr1.hasNext()) {
Object next = itr1.next();
ListIterator itr2 = l.listIterator( itr1.nextIndex() );
while (itr2.hasNext()) {
if (itr2.next() == next) {
itr1.remove();
break;
}
}
}
}
These are not the best solutions in terms of computational complexity. If memory space is not an issue the hashset solution is a better one regarding computational complexity.
But the question is about concurrent mofication through iterators and not about complexity optimization.

java.lang.IndexOutOfBoundsException while removing from ArrayList?

I am trying to remove an object from an ArrayList, My code is
ArrayList myArrayList=new ArrayList();
for(int index=0;index<20;index++){
myArrayList.add(index);
}
for(int removeIndex=0;removeIndex<=mArrayList;removeIndex++){
myArrayList.remove(removeIndex);
}
It is giving a java.lang.IndexOutOfBoundsException. How do I remove a number of objects from ArrayList?.
Of course, as soon as you remove the 0th item, the last item is now 18th, because the items are reindexed.
You can use several tricks, for example, remove starting from the end. Or remove the 0th item until the array is empty (or until you removed some predefined number of items).
Code:
for(int index = mArrayList.size() - 1; removeIndex >= 0; removeIndex--) {
myArrayList.remove(removeIndex);
}
or
for(int nremoved = mArrayList.size() - 1; nremoved >= 0; nremoved--) {
myArrayList.remove(0);
}
If you want to remove all the items, you can consider using clear() as well.
If you want to remove several positions from a list, you can try the following:
Collections.sort(positions); // needed if not already sorted
for (int i = positions.size() - 1; i >= 0; i--)
myArrayList.remove(positions.get(i));
List#clear() will remove all elements.
You have to check '<' while removing.
ArrayList myArrayList = new ArrayList();
for(int index=0;index<20;index++){
myArrayList.add(index);
}
for(int removeIndex=0;removeIndex<myArrayList.size();removeIndex++){
myArrayList.remove(removeIndex);
}
When you remove an element from ArrayList all its subsequent elements reduce their indeces by one.
Please refer to
public ArrayList.remove(int index)
if you needed to remove all elements from Array, and if is possible, then better would be
myArrayList = new ArrayList();
and inside loop you have to reset Array this way, because clear() or removeAll() doesn't works
You're comparing your removeIndex to the ArrayList itself instead of to ArrayList.size(). Also, you should use smaller than ( < ) instead of smaller than or equal to ( <= ) in the comparison, because using < results in an extra loop which causes an indexOutOfBoundsException.
Furthermore, start removing at the end of the ArrayList instead of at the beginning to avoid re-indexing of the elements, which can also cause an indexOutOfBoundsException. (Not in this case since you're comparing to Array.size() every loop. Instead you're removing every second item, as Vlad also mentions.)
In most common way use Iterator instead:
final Iterator<? extends T> it = collection.iterator();
while ( it.hasNext() ) {
T t = it.next();
if (isNeedToRemove(t)) {
it.remove();
}
}

How do I remove sequential elements from a Java ArrayList?

I'm a relatively new Java programmer and I'm having difficuly removing more than one element from an ArrayList. Ideally I'd like to do something like this:
ArrayList ar1 = new ArrayList();
ar1.add(...)
ar1.add(...)
ar1.add(...)
ar1.add(...)
for (int i = 0; i < 2; i++){
ar1.remove(i);
}
I think iterator might help, but I can't find an example that matches close enough to what I'm trying to do. Any help would be appreciated. Thanks.
Here's what you want to do:
ar1.subList(0, 2).clear();
This creates a sublist view of the first 2 elements of the list and then clears that sublist, removing them from the original list. The subList method exists primarily for this sort of thing... doing operations on a specific range of the list.
You can certainly do that
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
for (int i = 0; i < 2; i++) {
ar1.remove(i);
}
System.out.println(ar1);
Only pay attention that after you remove first element, other elements shift. Thus, calling
ar1.remove(0);
ar1.remove(1);
will effectively remove first and third elements from the list. This will delete first two elements, though:
ar1.remove(0);
ar1.remove(0);
For indexed removals from a list, you need to count backwards:
for (int i = 1; i >= 0; i--)
otherwise, your first removal shifts the items "above" it in the collection and you don't wind up removing the items you think you are removing.
You can use Collection.removeAll(toRemove) if you have a separate list of objects to remove.
http://download.oracle.com/javase/6/docs/api/java/util/Collection.html
If your collection is indexed based, like ArrayList is, you can call
remove(index)
to remove the element at the index. You can do that in a loop, but beware that removing shifts all the indexes as another answer points out.
If all you want to do is remove the first two elements from the list, then
list.remove(0);
list.remove(0);
should do it.
If you know the indexes of the items you want to remove, you can remove them in reverse order, without worrying about shifting indexes:
ArrayList ar1 = new ArrayList();
ar1.add("a");
ar1.add("b");
ar1.add("c");
ar1.add("d");
int[] indexesToRemove = {0,2,3};
Arrays.sort(indexesToRemove);
for (int i=indexesToRemove.length-1; i>=0; i--) {
ar1.remove(indexesToRemove[i]);
}
You could try this:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
int i = 0;
while (i < 2 && it.hasNext()) {
it.next();
it.remove();
i++;
}
Or, more generally:
List<Whatever> l = new ArrayList<Whatever>();
l.add(someStuff);
Iterator<Whatever> it = l.iterator();
while (it.hasNext()) {
Whatever next = it.next();
if (shouldRemove(next)) {
it.remove();
}
}
EDIT: I guess it depends if you are trying to remove particular indices or particular objects. It also depends on how much logic you need to decide if something should be removed. If you know the indices then remove them in reverse order. If you have a set of Objects to be removed, then use removeAll. If you want to iterate over the list and remove objects that match a predicate then use the above code.

Categories