3

Is there a more elegant way in Guava to remove items which meet a certain predicate from a collection and collect these removed items at the same time? See code below for an example.

public static void main(String[] a) {
    final List<String> list = new LinkedList<String>();

    list.add("...");
    ...

    final List<String> removedItems = new LinkedList<String>();

    Iterables.removeIf(list, new Predicate<String>() {
        public boolean apply(final String o) {
            if (...) { // some condition
                removedItems.add(o);
                return true;
            }
            return false;
        }
    });

    System.out.println(removedItems);
}

Thanks!

edit: My question is not about partitioning a list, but about removing elements from a collection and collecting them at the same time. I edited my question to avoid confusion.

John Deviao
  • 33
  • 1
  • 5
  • 1
    Related: http://stackoverflow.com/q/10547631/521799 – Lukas Eder Aug 12 '14 at 17:35
  • My question is not about partitioning a list, but about removing elements from a collection and collecting them at the same time. I edited my question to avoid confusion. – John Deviao Aug 13 '14 at 06:18
  • I understand. This is why I said *"related"*. Future visitors of this question might be actually looking for a way to partition a list into two lists, which is only subtly different from your approach. – Lukas Eder Aug 13 '14 at 06:38
  • Thanks for your comment! I think it was a good idea to point that out. – John Deviao Aug 13 '14 at 06:42
  • Are my changes sufficient to take this question off hold? – John Deviao Aug 13 '14 at 07:20

2 Answers2

1
Predicate<Integer> predicate = new Predicate<>() {
    public boolean apply(final Integer o) {
        return o <= 5;
    }
};

List<Integer> removed = Lists.newLinkedList(Iterables.filter(list, predicate));
Iterables.removeIf(list, predicate);
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
0

Collection.add() returns true if the call to add() modifies the collection. So, you can shortcut the if / else branch like this:

Iterables.removeIf(list, new Predicate<Integer>() {
    public boolean apply(final Integer o) {
        return o <= 5 && removedItems.add(o);
    }
});

With Java 8, this becomes

Iterables.removeIf(list, o -> o <= 5 && removedItems.add(o));

... or even (without Guava):

list.removeIf(o -> o <= 5 && removedItems.add(o));

Of course, not sure if this will be generally perceived as more readable :-)

Partitioning a collection by a predicate:

This question here deals with the problem from a different angle:

Library method to partition a collection by a predicate

Community
  • 1
  • 1
Lukas Eder
  • 211,314
  • 129
  • 689
  • 1,509
  • This works, but it's generally preferable to avoid side-effects (such as adding to a collection) in a function such as a `Predicate`. Better to have the predicate strictly determine the matching elements and let something else handle adding to a collection. – ColinD Aug 12 '14 at 17:31
  • @ColinD: I agree. Yet the question is very subjective already, so I figured that *"anything goes"* – Lukas Eder Aug 12 '14 at 17:33