How to find the latest date from the given map value in java

Viewed 1943

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

6 Answers

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()));
        }
});

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]

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);

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);

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

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.

Related