0

I have a list of houses in a number of cities. I am trying to use a filter in order to generate a list of the most expensive house in each city. I am unable to use conventional loops.

//This returns unique City Names
List unique = obList.stream()
    .map(x -> x.getCity())
    .distinct()
    .sorted()
    .collect(Collectors.toList());

//This returns the house with the highest price in that city
RAddress obReturn = obList.stream()
        .filter(x -> x.getCity().equalsIgnoreCase(sName))
        .sorted((x,y) -> (int)(y.getPrice() - x.getPrice()))
        .findFirst()
        .get();

I understand that combining these in some way is necessary to this problem but I cannot for the life of me figure out how...

Any and all help is appreciated.

Naman
  • 27,789
  • 26
  • 218
  • 353

1 Answers1

8

Use the groupingBy collector to collect all the houses in each city together; then use a downstream maxBy collector to keep just the most expensive house in each city:

obList.stream()
    .collect(
        groupingBy(
            x -> x.getCity(),
            maxBy(comparing(x -> x.getPrice())))

This returns a Map<CityType, Optional<HouseType>> (where CityType and HouseType are whatever the types of cities and houses are, respectively.

If you want a Map<CityType, HouseType> (that is, without the Optional, since you know the value is always present), wrap the downstream collector:

collectingAndThen(maxBy(...), Optional::get)
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • the "MaxBy" appears to not be a keyword, i must be doing something wrong. – user11376058 Feb 22 '20 at 19:39
  • 1
    [`maxBy` is a method in the `Collectors` class](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html#maxBy-java.util.Comparator-), as is `groupingBy`. – Andy Turner Feb 22 '20 at 19:43
  • 2
    @user11376058 Just to be explicit, the above code relies on `static import` from `Collectors` class with a return type of `Map>` if your city is of `String` type and price being `Integer`. – Naman Feb 23 '20 at 02:28
  • 1
    Or use `toMap(x -> x.getCity(), Function.identity(), maxBy(comparing(x -> x.getPrice())))`, now using [`BinaryOperator.maxBy(…)`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/function/BinaryOperator.html#maxBy(java.util.Comparator)). Then you don’t need to deal with `Optional`. See also [this Q&A](https://stackoverflow.com/q/57041896/2711488)… – Holger Feb 24 '20 at 09:10