番石榴 - 如何从列表中删除,基于谓词,跟踪删除的内容?

时间:2011-06-27 14:40:34

标签: java collections filtering guava predicate

我要过滤ArrayList,并使用各种Guava Predicate进行过滤。该列表只有50-100个元素。

我计划依次使用每个谓词Iterables.removeIf。它可能不是最有效的,但没关系(至少removeIf对RandomAccess列表有一些优化)

对于调试,我想简明地记录每个谓词的作用。 e.g。

Pred0 removed [a, c, g]
Pred1 removed []
Pred2 removed [b, f]

有一些明显的黑客解决方案,但你认为最干净的是什么?

对于奖励积分,它也应该合理有效。 ;)

5 个答案:

答案 0 :(得分:32)

我会在您的谓词代码中捕获已删除的元素。

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;
    }
}); 

答案 1 :(得分:5)

这可能是使用循环最简单的场合。

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;
       }
 }

答案 2 :(得分:4)

我会调查 observable谓词。这个想法:每次,谓词apply方法即将返回true,它会向听众发出通知:

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();
}

ObservableLoggerPredicate的装饰器:

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
}

PredicateLogger需要一个构造函数将自身添加为谓词的侦听器。它将接收通知并缓存触发事件的谓词(Event类需要该信息的适当字段)。 print将创建日志消息,reset将清除记录器缓存(用于下次运行)。

答案 3 :(得分:1)

我同意彼得的回复。

但是如果你想获得乐趣,你也可以将每个谓词包装在一个谓词中,该谓词将委托给包装的谓词,并存储在Map<Predicate, List<Foo>> removedByPredicate内返回true的值:

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;
    }
}

答案 4 :(得分:-4)

我想你需要:

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);