【问题标题】:How do I find the most recent joda DateTime in map?如何在地图中找到最新的 joda DateTime?
【发布时间】:2020-05-29 19:22:40
【问题描述】:

我有一张从 Firebase 实时数据库更新的地图,所以我事先不知道地图的大小。

在地图中,我有一个字符串作为键,一个 Joda DateTime 作为值。

我不知道如何遍历地图以返回最近的日期时间。

我会尽量解释得更好:

//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

      }

    }

你们能帮帮我吗? 非常感谢

编辑:对不起,还有一件事。我在 Android 中使用的最小 sdk 不允许我使用 Java 8。我必须使用 Java 7 功能。

【问题讨论】:

    标签: java android hashmap jodatime


    【解决方案1】:

    如何遍历地图以返回最近的日期时间

    Java 8+ 使用 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);
    

    任何使用for循环的Java版本:

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

    在上面,根据你需要最新的key、value还是entry(key+value),根据需要进行调整。


    最后只剩下一对最近日期的键/值

    最好的办法是在找到最新的条目之后替换地图,或者至少替换内容。

    Java 8+ 使用 Streams(替换地图):

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

    任何使用for循环的Java版本(替换内容):

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

    【讨论】:

    • 谢谢。有效。并感谢其他所有人的回答。
    【解决方案2】:

    您可以对映射值中的DateTime 对象使用.isAfter() 方法来检查一个在另一个之后。

    创建一个String mostRecentKey 变量或类似的东西,并将其设置为映射中的第一个键值。 然后遍历myMap.keySet(),将每个日期对象值与.isAfter() 中的最新值进行比较。最后,您将获得最近的日期。

    例如

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

    然后你有最近一个的键,你可以选择删除除那个之外的所有条目,保存值或任何你想要的。

    要删除除您找到的条目之外的所有条目,请在此处参考此问题:Remove all entries from HashMap where value is NOT what I'm looking for

    基本上,你可以这样做:

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

    编辑 - 忘了你不能修改你正在迭代的集合,稍微改变了方法。

    【讨论】:

    • 感谢您的回复。我尝试了您的建议,但得到了并发修改异常。请问您有什么建议可以避免这种情况吗?如果我不删除最近的日期,我可以在它完成迭代后记录最近的日期,但我仍然有一张包含所有最近日期的地图。
    【解决方案3】:

    Java 7 解决方案

    我在 Android 中使用的最小 SDK 不允许我使用 Java 8。我 必须使用 Java 7 功能。

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

    这个 sn-p 的输出在我的时区(在 jdk.1.7.0_67 上测试):

    最新的日期时间是 2020-03-01T02:23:45.000+01:00

    我们需要先检查map是否为空,因为Collections.max()如果是就会抛出异常。

    如果您需要从地图中删除所有条目,除了该条目或包含最新日期的条目:

            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}

    这有点棘手吗? retainAll 方法从集合中删除所有不在作为参数传递的集合中的元素。我们传递了一组只有一个元素,即最新的日期时间,因此所有其他元素都被删除。并且从我们从myMap.values() 获得的集合中删除元素会反映在我们从中获得集合的映射中,因此值不是最新日期的条目将被删除。所以这个调用就完成了。

    旁注:考虑 ThreeTenABP

    如果您还没有大量使用 Joda-Time,则可以考虑使用 java.time,它是现代 Java 日期和时间 API 以及 Joda-Time 的继承者。它已被向后移植,也可以在低 Android API 级别上运行。

    java.time 链接

    【讨论】:

      【解决方案4】:

      您也可以遍历 entrySet,保存最新的条目,然后删除所有内容并重新添加。

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

      【讨论】:

        猜你喜欢
        • 2021-05-16
        • 2010-11-15
        • 1970-01-01
        • 2011-06-07
        • 2016-07-19
        • 1970-01-01
        • 2015-05-22
        • 1970-01-01
        • 2011-02-09
        相关资源
        最近更新 更多