tags:

views:

239

answers:

4

Though for-each loop has many advantages but the problem is ,it doesn't work when you want to Filter(Filtering means removing element from List) a List,Can you please any replacement as even traversing through Index is not a good option..

+11  A: 

What do you mean by "filtering"? Removing certain elements from a list? If so, you can use an iterator:

for(Iterator<MyElement> it = list.iterator(); it.hasNext(); ) {
    MyElement element = it.next();
    if (some condition) {
      it.remove();
    }
}

Update (based on comments):

Consider the following example to illustrate how iterator works. Let's say we have a list that contains 'A's and 'B's:

A A B B A

We want to remove all those pesky Bs. So, using the above loop, the code will work as follows:

  1. hasNext()? Yes. next(). element points to 1st A.
  2. hasNext()? Yes. next(). element points to 2nd A.
  3. hasNext()? Yes. next(). element points to 1st B. remove(). iterator counter does NOT change, it still points to a place where B was (technically that's not entirely correct but logically that's how it works). If you were to call remove() again now, you'd get an exception (because list element is no longer there).
  4. hasNext()? Yes. next(). element points to 2nd B. The rest is the same as #3
  5. hasNext()? Yes. next(). element points to 3rd A.
  6. hasNext()? No, we're done. List now has 3 elements.

Update #2: remove() operation is indeed optional on iterator - but only because it is optional on an underlying collection. The bottom line here is - if your collection supports it (and all collections in Java Collection Framework do), so will the iterator. If your collection doesn't support it, you're out of luck anyway.

ChssPly76
@ChssPly76:Thanx For reply,Yes I meant with the same,but will it not affect the iteration when I am removing a element,at Iterator is From same INSTANCE.I want to remove element from the List(list)
Sam Rudolph
I'm pretty sure calling remove() on the iterator will affect the underlying list. It wouldn't really make sense otherwise.
Herms
It most certainly will remove the element from the underlying list. It will NOT affect the iteration, however - `remove()` is invoked on "current" element (the one that was returned from the last `next()` method call) and it does NOT change the "current" element. Next call to `next()` will return the following element from the list.
ChssPly76
Can you elaborate your answer,its some what unclear to me.pls help me
Sam Rudolph
Unfortunately Iterator#remove()'s javadoc has these two words which mostly go unnoticed; "optional operation". There isn't even way to check if but to try to use which means .remove() isn't reliable at all and shouldn't be used unless you're 110% sure it works.
Esko
@ChssPly76:can you please elaborate like how Iterator works,I am just curious to clear my concepts and gain more knowledge about the regarding topic
Sam Rudolph
@Esko:Great point,but what can be its ALTERNATE?
Sam Rudolph
@ChssPly76:Great Editing,I have a Doubt regarding step 3.like at step#3 we removed the element and if more operation is there in LOOP before step#4 will in that case i get an ERROR
Sam Rudolph
@ChssPly76:ERROR means Exception here
Sam Rudolph
"More operation" being what? Your "element" variable would still point to removed element, so you can do whatever you want with it. Attempting to modify the **List** itself, however, WILL result in exception - but you shouldn't be doing that while iterating anyway.
ChssPly76
A: 

ChssPly76's answer is the right approach here - but I'm intrigued as to your thinking behind "traversing through index is not a good option". In many cases - the common case in particular being that of an ArrayList - it's extremely efficient. (In fact, in the arraylist case, I believe that repeated calls to get(i++) are marginally faster than using an Iterator, though nowhere near enough to sacrifice readability).

Broadly speaking, if the object in question implements java.util.RandomAccess, then accessing sequential elements via an index should be roughly the same speed as using an Iterator. If it doesn't (e.g. LinkedList would be a good counterexample) then you're right; but don't dismiss the option out of hand.

Andrzej Doyle
Actaully I was talking abut this specific case only..
Sam Rudolph
Yes, but that doesn't change things - if in this specific case your list is an `ArrayList` (or similar) then index-based accessing is going to be **fast** (even slightly faster than using the Iterator), so it's a good option. If this is a generic library method which might take all kinds of lists, the implementation of which you have no control over - then it would be bad to assume (though you can still check for the interface implementation).
Andrzej Doyle
@dtsazza - you're completely right with regards to performance (+1). The issue with indexed loop, though, is it's extremely easy to mess it up if you need to remove some elements from your collection. Modifying index within for loop is just bad karma; and while loop requires additional outside counter and just feels less clean.
ChssPly76
A: 

I have had success using the

filter(java.util.Collection collection, Predicate predicate)

method of CollectionUtils in commons collections.

http://commons.apache.org/collections/api-2.1.1/org/apache/commons/collections/CollectionUtils.html#filter%28java.util.Collection,%20org.apache.commons.collections.Predicate)

Dusty Pearce
can you please elaborate your answer here, it will be very useful to me as well for others in future
Sam Rudolph
It's so annoying that these interfaces are not genericised. That's why I love the google collections
daveb
A: 

If you, like me, don't like modifying a collection while iterating through it's elements or if the iterator just doesn't provide an implementation for remove, you can use a temporary collection to just collect the elements you want to delete. Yes, yes, its less efficient compared to modifying the iterator, but to me it's clearer to understand whats happening:

List<Object> data = getListFromSomewhere();
List<Object> filter = new ArrayList<Object>();

// create Filter
for (Object item: data) {
  if (throwAway(item)) {
    filter.add(item);
  }
}

// use Filter
for (Object item:filter) {
  data.remove(item);
}

filter.clear();
filter = null;
Andreas_D