predicados - como eliminar un nodo de una lista en java
Guava-¿Cómo eliminar de una lista, en función de un predicado, el seguimiento de lo que se eliminó? (5)
Capturaría los elementos eliminados en tu código Predicado.
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;
}
});
Tengo un ArrayList
para filtrar y varios Predicate
Guava para filtrarlo. Esta lista tendrá solo 50-100 elementos.
Estaba planeando Iterables.removeIf
usando cada predicado por turno. Tal vez no sea lo más eficiente posible, pero no importa (al menos removeIf
tiene alguna optimización para las listas RandomAccess)
Para la depuración, quiero registrar concisamente lo que hizo cada predicado. p.ej
Pred0 removed [a, c, g]
Pred1 removed []
Pred2 removed [b, f]
Hay algunas soluciones obvias de corte, pero ¿qué sugieres que sean las más limpias?
Para puntos de bonificación, también debería ser razonablemente eficiente. ;)
Esta puede ser una ocasión cuando el uso de un bucle es más simple.
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;
}
}
Estoy de acuerdo con el autor de Peter.
Pero si quieres divertirte, también puedes ajustar cada uno de tus predicados dentro de un predicado que delegaría en el predicado envuelto, y almacenar los valores para los cuales se devuelve verdadero dentro de un 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;
}
}
Investigaría en predicados observables . La idea: cada vez que un método de apply
predicados está por volver verdadero, se lanzará una notificación a los oyentes:
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();
}
El ObservableLogger
es un decorador para 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
}
PredicateLogger
necesita un constructor que se agregue como oyente a los predicados. Recibirá las notificaciones y el caché de los predicados que dispararon los eventos (la clase Event
necesita un campo apropiado para esa información). print
creará el mensaje de registro, reset
borrará la memoria caché de registradores (para la próxima ejecución).
Supongo que necesitas:
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);