I have an ArrayList
to be filtered, and various Guava Predicate
s to filter it with. This list will have only 50-100 elements.
I was planning on
I guess you need:
Predicate<XXX> predicate1 = new Predicate<XXX>(){
@Override
public boolean apply(XXX input) {
if(...) //satisfy your filter
return true;
else
return false;
}};
Predicate<XXX> predicate2 = new Predicate<XXX>(){
@Override
public boolean apply(XXX input) {
if(...) //satisfy your filter
return true;
else
return false;
}};
Predicate allPredicates = Predicates.and(predicate1, predicate2);
//or Predicates.or(predicate1, predicate2);
Collection<XXX> list2 = Collections2.filter(list, allPredicates);
This may be an occasion when using a loop is simplest.
List<MyType> list =
Predicate<MyType>[] predicates =
Map<Predicate, List<MyType>> removed =
new LinkedHashMap<Predicate, List<MyType>>();
for(Iterator<MyType> iter=list.iterator();list.hasNext();) {
MyType mt = iter.next();
for(Predicate<MyType> pred: predicates)
if(pred.apply(mt)) {
List<MyType> mts = removed.get(pred);
if(mts == null)
removed.put(pred, mts = new ArrayList<MyType>());
mts.add(mt);
iter.remove();
break;
}
}
I would capture the removed elements in your Predicate code.
List<String> removedElements = Lists.newArrayList();
final Iterables.removeIf(list, new Predicate<String>() {
@Override
public boolean apply(String input) {
if ("a".equals(input)) {
removedElements.add(input);
return true;
}
return false;
}
});
I agree with Peter's anwser.
But if you want to have fun, you could also wrap each of your predicate inside a predicate which would delegate to the wrapped predicate, and store the values for which true is returned inside a Map<Predicate, List<Foo>> removedByPredicate
:
class PredicateWrapper implements Predicate<Foo> {
private Predicate<Foo> delegate;
public PredicateWrapper(Predicate<Foo> delegate) {
this.delegate = delegate;
}
@Override
public boolean apply(Foo foo) {
boolean result = delegate.apply(foo);
if (result) {
List<Foo> objectsRemoved = removedByPredicate.get(delegate);
if (objectsRemoved == null) {
objectsRemoved = Lists.newArrayList();
removedByPredicate.put(delegate, objectsRemoved);
}
objectsRemoved.add(foo);
}
return result;
}
}
I'd investigate in observable predicates. The idea: everytime, a predicates apply
method is about to return true, it will fire a notification to listeners:
Iterable<?> iterable = getIterable();
Collection<ObservablePredicate> predicates = getPredicates();
PredicatesLogger log = new PredicatesLogger(predicates); // listens to all predicates
for (ObservablePredicate pred : predicates) {
Iterables.removeIf(iterable, pred);
log.print();
log.reset();
}
The ObservableLogger
is a decorator for Predicate
:
public class ObservableLogger implements Predicate {
private Predicate predicate;
private List<Listener> listeners = new ArrayList<Listener>();
// usual stuff for observer pattern
@Override
public boolean apply(Object input) {
boolean result = predicate.apply(input);
fire(result);
return result;
}
// a fire method
}
The PredicateLogger
needs one constructor that adds itself as a listener to the predicates. It will receive the notifications and cache the predicates that fired the events (the Event
class needs an appropriate field for that information). print
will create the log message, reset
will clear the loggers cache (for the next run).