1

I have a map that is updated from Firebase Realtime Database, so I don't know the map size in advance.

In the map I have a String as key, and a Joda DateTime as value.

I don't know how to iterate through the map to return the most recent Datetime.

I'll try to explain better:

//on returning results from Realtime Database
  Map<String, DateTime> myMap = new HashMap<>();

    if(dataSnapshot.exists){

       for(DataSnapshot data:dataSnapshot.getChildren()){

           String key = data.getKey();
           DateTime dateTime = // I get the data and convert it to Datetime; no problem here; I can do it.

           myMap.put(key, dateTime);

       }

   //outside the Loop
   //HERE IS WHAT I NEED HELP WITH

      for(DateTime date:myMap.values()){

         // 1 - check if date is after the next date in map
         // 2 - if it is, then keep it
         // 3 - if it is not, then remove
         // 4 - in the end, only one pair of key/value with the most recent date is left

      }

    }

Can you guys please, help me? Thank you so much

EDIT: Sorry, one more thing. I'm using a minimum sdk in Android that doesn't ler me use Java 8. I have to use Java 7 features.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
EiteWald
  • 45
  • 5

4 Answers4

2

how to iterate through the map to return the most recent Datetime

Java 8+ using Streams:

// To get latest key (or entry)
String latestKey = myMap.entrySet().stream()
        .max(Entry::comparingByValue)
        .map(Entry::getKey) // skip this to get latest entry
        .orElse(null);
// To get latest value
DateTime latestValue = myMap.values().stream()
        .max(Comparator.naturalOrder())
        .orElse(null);

Any Java version using for loop:

Entry<String, DateTime> latestEntry = null;
for (Entry<String, DateTime> entry : myMap.entrySet()) {
    if (latestEntry == null || entry.getValue().isAfter(latestEntry.getValue()))
        latestEntry = entry;
}
String latestKey = (latestEntry != null ? latestEntry.getKey() : null);

In the above, adjust as needed depending on whether you need latest key, value, or entry (key+value).


in the end, only one pair of key/value with the most recent date is left

Best way is to replace the map, or at least replace the content, after finding the latest entry.

Java 8+ using Streams (replacing map):

myMap = myMap.entrySet().stream()
        .max(Comparator.comparing(Entry::getValue))
        .stream().collect(Collectors.toMap(Entry::getKey, Entry::getValue));

Any Java version using for loop (replacing content):

Entry<String, DateTime> latestEntry = null;
for (Entry<String, DateTime> entry : myMap.entrySet()) {
    if (latestEntry == null || entry.getValue().isAfter(latestEntry.getValue()))
        latestEntry = entry;
}
myMap.clear();
if (latestEntry != null)
    myMap.put(latestEntry.getKey(), latestEntry.getValue());
Community
  • 1
  • 1
Andreas
  • 154,647
  • 11
  • 152
  • 247
1

You can use the .isAfter() method on the DateTime objects in the map values to check if one is after the other.

Create a String mostRecentKey variable or something similar and set it to the first key value in the map. Then iterate through myMap.keySet(), comparing each date object value to the most recent one with .isAfter(). At the end, you will have the most recent date.

e.g

String mostRecentKey;
for (String dateKey : myMap.keySet()){
    if (mostRecentKey == null) {
        mostRecentKey = dateKey;
    }
    // 1 - check if date is after the next date in map
    if (myMap.get(dateKey).isAfter(myMap.get(mostRecentKey))) {
        mostRecentKey = dateKey;
    }
}

Then you have the key of the most recent one, and you can choose to delete all entries except that one, save the value or whatever you want.

To delete all but the entry you found, refer to this question here: Remove all entries from HashMap where value is NOT what I'm looking for

Basically, you can do something like this:

myMap.entrySet().removeIf(entry -> !entry.getKey().equals(mostRecentKey));

Edit - Forgot you can't modify a collection you are iterating through, changed method slightly.

Zen Monkey
  • 101
  • 6
  • Thanks for the response. I tried your suggestion, but got a Concurrent Modification Exception. Do you have any suggestions to avoid this, please? If I dont remove the less recent date, I can log the most recent date after it finishes iteration, but I still have a map with all the less recent dates. – EiteWald Feb 14 '20 at 02:19
1

Java 7 solution

I'm using a minimum sdk in Android that doesn't ler me use Java 8. I have to use Java 7 features.

    Map<String, DateTime> myMap = new HashMap<>();
    myMap.put("a", new DateTime("2020-01-31T23:34:56Z"));
    myMap.put("b", new DateTime("2020-03-01T01:23:45Z"));
    myMap.put("m", new DateTime("2020-03-01T01:23:45Z"));
    myMap.put("c", new DateTime("2020-02-14T07:14:21Z"));

    if (myMap.isEmpty()) {
        System.out.println("No data");
    } else {
        Collection<DateTime> dateTimes = myMap.values();
        DateTime latest = Collections.max(dateTimes);

        System.out.println("Latest date-time is " + latest);
    }

Output from this snippet is in my time zone (tested on jdk.1.7.0_67):

Latest date-time is 2020-03-01T02:23:45.000+01:00

We need to check first whether the map is empty because Collections.max() would throw an exception if it is.

If you need to delete all entries from the map except that or those holding the latest date:

        dateTimes.retainAll(Collections.singleton(latest));
        System.out.println(myMap);

{b=2020-03-01T02:23:45.000+01:00, m=2020-03-01T02:23:45.000+01:00}

Is it a little bit tricky? The retainAll method deletes from a collection all elements that are not in the collection passed as argument. We pass a set of just one element, the latest date-time, so all other elements are deleted. And deleting elements from the collection we got from myMap.values() is reflected back in the map from which we got the collection, so entries where the value is not the latest date are removed. So this call accomplishes it.

Side note: consider ThreeTenABP

If you are not already using Joda-Time a lot, you may consider using java.time, the modern Java date and time API and the successor of Joda-Time, instead. It has been backported and works on low Android API levels too.

java.time links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

You could iterate through entrySet as well, save the latest entry then remove everything and add that one back in.

    Map<String, DateTime> myMap = new HashMap<>();
    ....

    Entry<String, DateTime> latest = myMap.entrySet().iterator().next();
    for(Entry<String, DateTime> date:myMap.entrySet()){

         // 1 - use isAfter method to check whether date.getValue() is after latest.getValue()
         // 2 - if it is, save it to the latest
      }
    myMap.clear();
    myMap.put(latest.getKey(), latest.getValue());
Sunny
  • 605
  • 10
  • 35