Question: I have two tables `tblReservation` and `tblBooking`. The `tblReservation` has an `ID` column and an Event Name column. `tblBooking` has it's own `ID` column and has the Reservation ID column as well (foreign key), and then EventStart and EventEnd columns.

Basically I am doing the following:

```
SELECT DISTINCT 
    B1.ReservationID,
    B1.EventStart,
    B1.EventEnd,
    tblReservation.EventName
FROM        
    tblBooking AS B1 
INNER JOIN
    tblReservation ON B1.ReservationID = tblReservation.ID
WHERE       
    B1.EventEnd = (SELECT MAX(B2.EventEnd)
                   FROM tblBooking AS B2
                   WHERE B2.ReservationID = B1.ReservationID)

```

I tried this subquery to only pull one Reservation ID per booking. Essentially I want these results:

```
Reservation ID     EventStart    EventEnd     EventName
1                  1/1/18        1/2/18       Event 1
2                  1/2/18        1/3/18       Event 2 
3                  1/4/18        1/6/18       Event 3

```

Instead I'm getting:

```
Reservation ID     EventStart    EventEnd     EventName
1                  1/1/18        1/1/18       Event 1
1                  1/2/18        1/2/18       Event 1
2                  1/2/18        1/2/18       Event 2
2                  1/3/18        1/3/18       Event 2 

```

Answer: 
> 
> I was wondering if there was a way to simplify this? I
> 
> 
> 

The stream way is probably not what you need for your requirement and your code is actually simple. 

Streams allow to pass from an input (`Stream<Foo>`) to a result (`Foo`, `List<String>`...) thanks to multiple intermediary operations (filter, map, reduce, stream a collected result...).  

Each stream operation relies on the returned stream of the next operation :  

To simplify it would give a chain :

> 
> a -> b (use a)-> c (uses b)-> d (uses c)-> e (uses d)
> 
> 
> 

Actually you code cannot rely on such a logic because the returned `List<String>` doesn't need only to return the list of names that have duplicates, that could be written such as :

```
List<String> duplicates =     
    animals.stream()
           .collect(Collectors.groupingBy(Animal::getName))
           .entrySet().stream()
           .filter(e -> e.getValue().size() > 1)
           .map(Entry::getKey)
           .collect(Collectors.toList());

```

you want return a `List` of each duplicate appearition in the order these occur.  

It means that you don't map `Stream<Animal>` -> `Stream<String>` such as 

> 
> a->b (uses a)
> 
> 
> 

because you need to filter out the element if the Animal name was not added in the result ... but a stream is not designed to populate incrementally the result. So you are stuck. 

---

You could write this one but as said that is really not a simplification and still it doesn't apply the same logic as the order of dup names is not the same as in your code :

```
List<String> duplicates = 
          animals.stream()
                 .collect(Collectors.groupingBy(Animal::getName, LinkedHashMap::new, Collectors.toList()))
                 .values().stream()
                 .flatMap(l-> l.stream().skip(1)) 
                 .map(Animal::getName)
                 .collect(Collectors.toList());

```
Do not re-invent the wheel and use libraryies like [commns-collection.substract()](https://commons.apache.org/proper/commons-collections/apidocs/org/apache/commons/collections4/CollectionUtils.html#subtract-java.lang.Iterable-java.lang.Iterable-)

```
// I have not tested the code, but I think you get the idea
Set<> unique = new HashSet(animals)
Collection<> dublicates = CollectionUtil.subtract(animals, unique)

```