3

I have a List<Hotel>, each Hotel have a BigDecimal minSellingPrice, I want to get the Hotel with the minimum selling price.

I was able to achieve this via this code

hotels.stream().min((h1, h2) -> h1.getMinSellingPrice().compareTo(h2.getMinSellingPrice())).get()

But what if 3 hotels in the list have the minimum selling price in common, so the list have 50 hotels, lowest minSellingPrice is 100, 3 hotels out of 50 have a minSellingPrice of 100.

How can I get a list of those 3 hotels so I can operate on them? The only thing I thought of is getting the minimum price via map and min then querying the list for the items that have this lowest price, but that doesn't sound too nice.

prettyvoid
  • 3,446
  • 6
  • 36
  • 60
  • Filter `hotels.stream()` for the value you get above. Technically, you only need to traverse once since no backtracking is required here. Maybe create a custom filter that adds to another list if multiple occurrences are found. – Mad Physicist Oct 18 '16 at 16:17
  • 1
    See [“How to force max() to return ALL maximum values in a Java Stream?”](http://stackoverflow.com/q/29334404/2711488), the logic for minimum is the same… – Holger Oct 18 '16 at 17:32

4 Answers4

3

You could try below to get the min hotel

Hotel min = hotels.stream().min(Comparator.comparing(Hotel::getSellingPrice)).orElse(null);

in order to get more than one hotels, you need to use groupingBy

Map<BigDecimal, List<Hotel>> groupedHoted = hotels.stream().collect(Collectors.groupingBy(Hotel::getSellingPrice, TreeMap::new, Collectors.toList()));

Update

edited as per comments

groupedHoted = new TreeMap<>(hotels.stream().collect(Collectors.groupingBy(Hotel::getSellingPrice)));

using reduce (less recommended)

    Map<BigDecimal, List<Hotel>> sorted = hotels.stream().reduce(new TreeMap<BigDecimal, List<Hotel>>(), (map, hotel) -> {
        if (map.get(hotel.getSellingPrice()) == null) {
            map.put(hotel.getSellingPrice(), new ArrayList<>());
        }
        map.get(hotel.getSellingPrice()).add(hotel);
        return map;
    }, (map1, map2) -> {
        map1.putAll(map2);
        return map1;
    });

output

{10=[Hotel [sellingPrice=10], Hotel [sellingPrice=10]], 20=[Hotel [sellingPrice=20], Hotel [sellingPrice=20]], 30=[Hotel [sellingPrice=30]]}
Saravana
  • 12,647
  • 2
  • 39
  • 57
  • @erickson I didn't copy you, I have answered similar questions already in SO, I understood the question wrongly then I corrected my answer – Saravana Oct 18 '16 at 16:44
  • @erickson edited my answer, the map it sorted, user can iterate and get the number of hotels they want – Saravana Oct 18 '16 at 17:27
  • 1
    Thanks. By the way there is no difference between your 2nd code block and the 3rd. It was tough for me to accept an answer so I accepted the one that posted earlier. Appreciated however :) – prettyvoid Oct 19 '16 at 12:56
1

If you want to sort the list of Hotels:

Comparator<Hotel> comp = new Comparator<Hotel>() {
            public int compare(Hotel o1, Hotel o2) {
                return o1.getMinSellingPrice() - o2.getMinSellingPrice();
            }
        };

hotels = hotels.stream().sorted(comp).collect(Collectors.toList());

This uses a comparator, documentation here.

Or to return the minimum selling price in the list:

hotels.stream().map(i -> i.getMinSellingPrice()).min(Comparator.naturalOrder()).get());

This simply maps the list of hotels to a list of their minSellingPrice's, then takes the smallest value.

Liam Ferris
  • 1,786
  • 2
  • 18
  • 38
1

Use the form of Collectors.groupingBy() that allows you to specify the type of Map to use, and specify a SortedMap or NavigableMap implementation. Then you can easily retrieve the collection of minimal elements from the result.

NavigableMap<BigDecimal, List<Hotel>> hotelByPrice = hotels.stream()
    .collect(Collectors.groupingBy(Hotel::getMinSellingPrice, TreeMap::new, Collectors.toList()));
List<Hotel> cheapest = hotelByPrice.firstEntry().getValue();
erickson
  • 265,237
  • 58
  • 395
  • 493
0

Another possibility.

List<Hotel> minHotels = hotels.stream()
    .filter(h -> h.minSellingPrice == hotels.stream()
        .map(Hotel::getMinSellingPrice).sorted().findFirst().orElse(null))
    .collect(Collectors.toList());
JynXXedRabbitFoot
  • 996
  • 1
  • 7
  • 17