21

I would like to remove an element from an ArrayList in Java if it meets a certain criteria.

ie:

for (Pulse p : pulseArray) {
    if (p.getCurrent() == null) {
        pulseArray.remove(p);
    }
}

I can understand why this does not work, but what is a good way to do this?

4
  • Not only will this fail to work, but even if it did work it would have terrible performance. It's an O(n^2) algorithm because you have to check every element of the array up to the one you are removing. The optimal algorithm is O(n). Commented Nov 9, 2012 at 21:59
  • 1
    @MarkByers "check every element of the array" is O(n), why do you think this is O(n^2)? Commented Nov 9, 2012 at 22:50
  • 1
    @jlordo: list.remove(object) is an O(n) operation. It gets executed O(n) times because it's in a loop. That gives O(n*n). Commented Nov 9, 2012 at 22:51
  • @MarkByers Thank you. I thought remove(Object) is O(1), but Documentation proves your point. Commented Nov 9, 2012 at 22:55

10 Answers 10

51

You can use Collection::removeIf(Predicate filter) (available from Java8 onwards), here is a simple example:

final Collection<Integer> list = new ArrayList<>(Arrays.asList(1, 2));
list.removeIf(value -> value < 2);
System.out.println(list); // outputs "[2]"
Sign up to request clarification or add additional context in comments.

2 Comments

Don't use this if you want to support the old APIs. Crashed for me with a NoClassDefFoundError on 4.4.
@Sagar, I added a hint about this.
27

You must use an Iterator to iterate and the remove function of the iterator (not of the list) :

Iterator<Pulse> iter = pulseArray.iterator();
while (iter.hasNext()) {
  Pulse p = iter.next();
  if (p.getCurrent()==null) iter.remove();
}

Note that the Iterator#remove function is said to be optionnal but it is implemented by the ArrayList's iterator.

Here's the code of this concrete function from ArrayList.java :

765         public void remove() {
766             if (lastRet < 0)
767                 throw new IllegalStateException();
768             checkForComodification();
769 
770             try {
771                 ArrayList.this.remove(lastRet);
772                 cursor = lastRet;
773                 lastRet = -1;
774                 expectedModCount = modCount;
775             } catch (IndexOutOfBoundsException ex) {
776                 throw new ConcurrentModificationException();
777             }
778         }
779 
780         final void checkForComodification() {
781             if (modCount != expectedModCount)
782                 throw new ConcurrentModificationException();
783         }
784     }

The expectedModCount = modCount; line is why it won't throw an exception when you use it while iterating.

2 Comments

Technically, the enhanced-for-loop is using an iterator. Can you give an example of what he'd have to do? Also, it should be noted that not all iterators will actually implement the remove method, and would throw a 'not implemented' exception.
@Clockwork-Muse Yes but the internal ArrayList's iterator does implement it.
4

No need to use iterator. With Java 8 (streaming and filtering capability and lambdas) you can accomplish it using one line. For eg. the required code that does the operation you specified will be :

pulseArray = pulseArray.stream().filter(pulse -> pulse != null).collect(Collectors.toList());

2 Comments

You can also use Objects::nonNull.
shouldn't it be ... -> pulse.getCurrent() != null)...
3

When you are removing the element from the same list, the index gets disturbed. Try little differently as below:

  for (int i=0; i < pulseArray.size(); i++) {
     Pulse p = (Pulse)pulseArray.get(i);
     if (p.getCurrent() == null) {
        pulseArray.remove(p);
        i--;//decrease the counter by one
     }
  }

1 Comment

Thanks It worked fine for my lower API version source. For higher versions -> removeIf works as charm.
3

You can implement interface Predicate overriding abstract method boolean test(T);

Use removeIf(Predicate p) method to remove all matching elements from your list.

For example:

List<Book> bookList = new ArrayList<>();
bookList.add(new Book(101, "bookname1"));
bookList.add(new Book(102, "booknamelong2"));
bookList.removeIf(new LongBookNames())

public class LongBookNames implements Predicate<Book> {

  @Override
  public boolean test(Book book) {
    return book.getBookName.length() >10;
  }
}

Comments

2

As an alterative to using an iterator, you can use the Guava collections library. This has the advantage of being more functional (if you are into that sort of thing):

Predicate<Pulse> hasCurrent = new Predicate<Pulse>() {
  @Override public boolean apply(Pulse input) {
    return (input.getCurrent() != null);
  }
};

pulseArray = Lists.newArrayList(Collections2.filter(pulseArray, hasCurrent));

Comments

1

To remove elements from ArrayList based on a condition or predicate or filter, use removeIf() method. You can call removeIf() method on the ArrayList, with the predicate (filter) passed as argument. All the elements that satisfy the filter (predicate) will be removed from the ArrayList.

arraylist.removeIf(element -> (Objects.equals(element.getId(), id)));

Comments

0

You can't alter a collection that you're iterating through using methods on the collection. However, some iterators (including iterators on ArrayLists) support a remove() method that allows you to remove methods in the order that you're iterating.

Iterator<Pulse> iterator = pulseArray.iterator();
while (iterator.hasNext()) {
  Pulse p = iterator.next();
  if (p.getCurrent() == null) {
    iterator.remove();
  }
}

Comments

0

Below one is used when Single ArrayList have multiple types Objects and one object have count == 0 then it removed from pulseArray

Constants.java

public class ViewType {
    public static final int PULSE = 101;
    public static final int HEARTBEAT = 102;
}

BaseModel.java (This is Base Model)

public interface BaseModel {
    int getViewType();
}

PulseModel.java (which implements with BaseModel)

public class PulseModel implements BaseModel {

    @Override
    public int getViewType() {
        return Constants.ViewType.PULSE;
    }

    @SerializedName("PulseId")
    @Expose
    private String pulseId;
    @SerializedName("Count")
    @Expose
    private String count;
}

Remove PulseModel object from pulseArray in which Count = 0

pulseArray.removeIf(
     (BaseModel model) -> {
         boolean remove = false;
         if (model instanceof PulseModel) {
              remove = (((PulseModel) model).getCount() == 0);
              if (remove) {
                 //Success
              }
         }
         return remove;
      });

Comments

-2

Using an Iterator would give you the power of modifying the list while iterating through the arraylist

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.