Can Java 8 Streams operate on an item in a collection, and then remove it?

前端 未结 8 1280
不知归路
不知归路 2020-12-23 14:22

Like just about everyone, I\'m still learning the intricacies (and loving them) of the new Java 8 Streams API. I have a question concerning usage of streams. I\'ll provide a

相关标签:
8条回答
  • 2020-12-23 14:51

    if I understand your question correctly:

    set = set.stream().filter(item -> {
        if (item.qualify()) {
            ((Qualifier) item).operate();
            return false;
        }
        return true;
    }).collect(Collectors.toSet());
    
    0 讨论(0)
  • 2020-12-23 14:58

    In one line no, but maybe you could make use of the partitioningBy collector:

    Map<Boolean, Set<Item>> map = 
        set.stream()
           .collect(partitioningBy(Item::qualify, toSet()));
    
    map.get(true).forEach(i -> ((Qualifier)i).operate());
    set = map.get(false);
    

    It might be more efficient as it avoids iterating the set two times, one for filtering the stream and then one for removing corresponding elements.

    Otherwise I think your approach is relatively fine.

    0 讨论(0)
  • 2020-12-23 14:59

    There are many approaches. If you use myList.remove(element) you must override equals(). What I prefer is:

    allList.removeIf(item -> item.getId().equals(elementToDelete.getId()));
    

    Good luck and happy coding :)

    0 讨论(0)
  • 2020-12-23 15:00

    You can do it like this:

    set.removeIf(item -> {
        if (!item.qualify())
            return false;
        item.operate();
        return true;
    });
    

    If item.operate() always returns true you can do it very succinctly.

    set.removeIf(item -> item.qualify() && item.operate());
    

    However, I don't like these approaches as it is not immediately clear what is going on. Personally, I would continue to use a for loop and an Iterator for this.

    for (Iterator<Item> i = set.iterator(); i.hasNext();) {
        Item item = i.next();
        if (item.qualify()) {
            item.operate();
            i.remove();
        }
    }
    
    0 讨论(0)
  • 2020-12-23 15:00

    What you really want to do is to partition your set. Unfortunately in Java 8 partitioning is only possible via the terminal "collect" method. You end up with something like this:

    // test data set
    Set<Integer> set = ImmutableSet.of(1, 2, 3, 4, 5);
    // predicate separating even and odd numbers
    Predicate<Integer> evenNumber = n -> n % 2 == 0;
    
    // initial set partitioned by the predicate
    Map<Boolean, List<Integer>> partitioned = set.stream().collect(Collectors.partitioningBy(evenNumber));
    
    // print even numbers
    partitioned.get(true).forEach(System.out::println);
    // do something else with the rest of the set (odd numbers)
    doSomethingElse(partitioned.get(false))
    

    Updated:

    Scala version of the code above

    val set = Set(1, 2, 3, 4, 5)
    val partitioned = set.partition(_ % 2 == 0)
    partitioned._1.foreach(println)
    doSomethingElse(partitioned._2)`
    
    0 讨论(0)
  • 2020-12-23 15:05

    Nope, your implementation is probably the simplest one. You might do something deeply evil by modifying state in the removeIf predicate, but please don't. On the other hand, it might be reasonable to actually switch to an iterator-based imperative implementation, which might actually be more appropriate and efficient for this use case.

    0 讨论(0)
提交回复
热议问题