Java Guava - 如何根据谓词从列表中删除,跟踪已删除的内容?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6494614/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-16 06:23:05  来源:igfitidea点击:

Guava - How to remove from a list, based on a predicate, keeping track of what was removed?

javacollectionsfilteringguavapredicate

提问by Iain

I have an ArrayListto be filtered, and various Guava Predicates to filter it with. This list will have only 50-100 elements.

我有一个ArrayList要过滤的,还有各种 GuavaPredicate来过滤它。此列表将只有 50-100 个元素。

I was planning on Iterables.removeIfusing each predicate in turn. It is perhaps not maximally efficient but never mind (at least removeIfhas some optimization for RandomAccess lists)

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

For debugging, I want to concisely log what each predicate did. e.g.

对于调试,我想简洁地记录每个谓词所做的事情。例如

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

There are some obvious hack solutions but what would you suggest as the cleanest?

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

For bonus points, it should be reasonably efficient too. ;)

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

采纳答案by JanRavn

I would capture the removed elements in your Predicate code.

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

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

回答by Peter Lawrey

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

回答by u290629

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

回答by JB Nizet

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:

但是,如果您想玩得开心,您也可以将每个谓词包装在一个谓词中,该谓词将委托给包装后的谓词,并将返回 true 的值存储在 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;
    }
}

回答by Andreas Dolk

I'd investigate in observable predicates. The idea: everytime, a predicates applymethod is about to return true, it will fire a notification to listeners:

我会在observable predicates 中进行调查。想法:每次,谓词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();
}

The ObservableLoggeris a decorator for Predicate:

ObservableLogger是一个装饰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 PredicateLoggerneeds 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 Eventclass needs an appropriate field for that information). printwill create the log message, resetwill clear the loggers cache (for the next run).

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