9

I'm having hash map with below values, in values I've date as string data type. I would like to compare all the dates which is available in map and extract only one key-value which has a very recent date.

I would like to compare with values not keys.

I've included the code below

import java.util.HashMap;
import java.util.Map;

public class Test {

  public static void main(String[] args) {

      Map<String, String> map = new HashMap<>();
      map.put("1", "1999-01-01");
      map.put("2", "2013-10-11");
      map.put("3", "2011-02-20");
      map.put("4", "2014-09-09");

      map.forEach((k, v) -> System.out.println("Key : " + k + " Value : " + v));
    }

}

The expected output for this one is:

Key 4 Value 2014-09-09

Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
learn groovy
  • 487
  • 4
  • 11
  • 28
  • he needs the largest value, not key – mangusta Oct 08 '19 at 01:44
  • 1
    OK, try https://stackoverflow.com/questions/109383/sort-a-mapkey-value-by-values – Scary Wombat Oct 08 '19 at 01:49
  • Design error. Don’t put your dates into your map as strings. Put `LocalDate` objects. The rest of the code will probably be the same, save declaration of the type of the map. – Ole V.V. Oct 08 '19 at 05:15
  • Related: [Finding the keys of map with the highest values (equality may occur)](https://codereview.stackexchange.com/questions/153346/finding-the-keys-of-map-with-the-highest-values-equality-may-occur) (on Stack Exchange Code Review). – Ole V.V. Oct 08 '19 at 05:18

6 Answers6

5

Use Collections.max with entrySet

Entry<String, String> max = Collections.max(map.entrySet(), Map.Entry.comparingByValue());

or

Entry<String, String> max = Collections.max(map.entrySet(),
    new Comparator<Entry<String, String>>() {
        @Override
        public int compare(Entry<String, String> e1, Entry<String, String> e2) {
            return LocalDate.parse(e1.getValue()).compareTo(LocalDate.parse(e2.getValue()));
        }
});
bathudaide
  • 737
  • 1
  • 4
  • 12
3

This should work

    Optional<Map.Entry<String, String>> result = map.entrySet().stream().max(Comparator.comparing(Map.Entry::getValue));
    System.out.println(result);

output is Optional[4=2014-09-09]

user51
  • 8,843
  • 21
  • 79
  • 158
3

At the first glance, using String literals to represent Date is not a good approach and makes it more fragile and error prone. You would rather use LocalDate in the first place. However, with the assumption that you don't have any control over that data format (for instance, say, it is coming from another third party system), we can still devise an approach that solves the problem at hand. Here's how it looks.

Entry<String, String> maxEntry = map.entrySet().stream()
    .max(Comparator.comparing(e -> LocalDate.parse(e.getValue())))
    .orElseThrow(IllegalArgumentException::new);

The LocalDate.parse is used to convert the string representation of the date into a LocalDate which is a Comparable. That Comparable is then passed as a key to the Comparator construction method. And here's the output key-value pair upon the successful execution:

4=2014-09-09

If you can merely dispense with the String representation of date as suggested above, then you can make the above solution much more simpler and succinct.

Entry<String, LocalDate> maxEntry = map.entrySet().stream()
    .max(Map.Entry.comparingByValue())
    .orElseThrow(IllegalArgumentException::new);
Ravindra Ranwala
  • 20,744
  • 6
  • 45
  • 63
1

This should provide the newest (aka largest) date as compared to the others.

      String max = map.values().stream().reduce("0000-00-00",
            (a, b) -> b.compareTo(a) >= 0 ? b
                  : a);

If you also want the key, then do this and return a Map.Entry. Requires Java 9+

         Entry<String, String> ent =
            map.entrySet().stream().reduce(Map.entry("0", "0000-00-00"),
                  (a, b) -> b.getValue().compareTo(a.getValue()) >= 0 ? b
                        : a);

         System.out.println(ent.getKey() + " -> " ent.getValue());

This presumes your map is non-empty. if it is empty, then it returns a null. Works with Java 8+

        Entry<String, String> ent = map.entrySet().stream().reduce(
            (a, b) -> b.getValue().compareTo(a.getValue()) >= 0 ? b
                  : a).orElseGet(() -> null);
WJS
  • 36,363
  • 4
  • 24
  • 39
1

You can parse the string into LocalDate and sort it in reverse order

 Entry<String, String> res = map.entrySet()
                                .stream()
                                .sorted(Comparator.comparing((Entry<String, String> entry)->LocalDate.parse(entry.getValue())).reversed())
                                .findFirst()
                                .orElse(null);  // if not present return null or empty Entry
Ryuzaki L
  • 37,302
  • 12
  • 68
  • 98
1

You can do either :

import java.util.Map.Entry;

Entry<String, String> maxEntry = map.entrySet()
                                    .stream()
                                    .max(Entry.comparingByValue());
                                    .orElseThrow(NoSuchElementException::new);   

or :

Entry<String, String> max = Collections.max(map.entrySet(), Entry.comparingByValue());

Both will produce the same result.

ETO
  • 6,970
  • 1
  • 20
  • 37