3

I have a list of locations returned by Google places API and decided to find a Place with a lowest price.

Here is how I implemented it with Java 8:

BigDecimal lowestPrice = places.stream()
                .collect(Collectors.groupingBy(Place::getPrice, Collectors.counting()))
                .entrySet().stream().min(Map.Entry.comparingByValue())
                .map(Map.Entry::getKey)
                .orElse(BigDecimal.ZERO); 

It returns me the lowest price but it'll be great to get a name of the Place as well (it has a name attribute).

How can I also return a name of the place with a lowest price?

6
  • Do you want to return both the name and the price? Commented Dec 9, 2018 at 21:37
  • @GBlodgett I want to use the name an price values later so yes I need both. Commented Dec 9, 2018 at 21:37
  • 2
    Try places.stream().min(Comparator.comparing(Place::getPrice)).get(); Commented Dec 9, 2018 at 21:41
  • @HadiJ OP is comparing by the count not price. Commented Dec 9, 2018 at 21:45
  • 1
    @HadiJ Right, cool since it's ambiguous what the OP is after I'll include both solutions then :). Commented Dec 9, 2018 at 21:55

3 Answers 3

9

Why don't you return the whole Place object ?

places.stream().min(Comparator.comparing(Place::getPrice)).get()

Sign up to request clarification or add additional context in comments.

1 Comment

Good solution. You should rather return an Optional. .get() can make an exception if the list is empty.
4

Firstly, it's really unclear what you want as at first, you seem to say that

I have a list of locations returned by Google places API and decided to find a Place with a lowest price.

then at the bottom of your description, you say that:

It returns me the lowest price but it'll be great to get a name of the Place as well (it has a name attribute).

as if the latter seems to be what you want?

Nevertheless, here are both solutions:

if you want to find the min value by the count after grouping for whatever reason that may be... then you could do something along the lines of:

 places.stream()
       .collect(Collectors.groupingBy(Place::getPrice))
       .entrySet().stream()
       .min(Comparator.comparingInt((Map.Entry<Integer, List<Place>> e) -> e.getValue().size()))
       .map(e -> new SimpleEntry<>(e.getKey(), e.get(0)));  

note that above i've used Integer as the entry key, feel free to change this to the appropriate type if it's not an Integer.


Otherwise, if you're simply after the object with the lowest price then you can do:

places.stream().min(Comparator.comparingInt(Place::getPrice));

or:

Collections.min(places, Comparator.comparingInt(Place::getPrice));

There's no need for grouping and all the stuff going on.

Comments

2

You should find the Place with the lowest price, not the lowest price and Place that propose it:

places.stream()
      .min(Comparators.comparing(Place::getPrice)) // compare by Price. Should use a second criteria for Place with same Price
      ; // return Optional<Place>

If you really need to get the count, you can still do it:

  BigDecimal lowestPrice = places.stream()
            .collect(Collectors.groupingBy(Place::getPrice, toList()))
            .entrySet()
            .stream()
            .min(Map.Entry.comparingByKey()) // Optional<Map.Entry<BigDecimal, List<Place>>
            .map(Map.Entry::getValue)
            // places = List<Place>, you can use size()
            .ifPresent(places -> places.forEach(System.out::println));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.