Java 分组并从地图中获取最新的月份数据

Java 分组并从地图中获取最新的月份数据,java,java-8,hashmap,Java,Java 8,Hashmap,我有一张地图如下: rupFeedDC.forEach(rl -> rl.getTransactionDate() .toLocalDateTime() .truncatedTo(ChronoUnit.DAYS)); Map<Timestamp, List<STUP>> timestampListMap = rupFeedDC.stream()

我有一张地图如下:

rupFeedDC.forEach(rl -> rl.getTransactionDate()
                          .toLocalDateTime()
                          .truncatedTo(ChronoUnit.DAYS));

Map<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
    .collect(Collectors.groupingBy(STUP::getTransactionDate));
我只想要钥匙2017年4月23日,因为它包含最近一个月。有人能告诉我该怎么做吗?

因为您的密钥是java.sql.Timestamp,所以您可以利用它实现可比性这一事实。修改流管道以生成树映射,其中键按升序排序,最后一个键将是最新的时间戳:

TreeMap<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
             .collect(Collectors.groupingBy(STUP::getTransactionDate,
                                            TreeMap::new,
                                            Collectors.toList()));
Timestamp last = timestampListMap.lastKey();
Timestamp latest = rupFeedDC.stream()
    .map(STUP::getTransactionDate)
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));
因为您的密钥是java.sql.Timestamp,所以您可以利用它实现可比较性这一事实。修改流管道以生成树映射,其中键按升序排序,最后一个键将是最新的时间戳:

TreeMap<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
             .collect(Collectors.groupingBy(STUP::getTransactionDate,
                                            TreeMap::new,
                                            Collectors.toList()));
Timestamp last = timestampListMap.lastKey();
Timestamp latest = rupFeedDC.stream()
    .map(STUP::getTransactionDate)
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));

您可以在地图的键上迭代并查找最新的

Set<String> keys = map.keySet();
        Date latest = null;

        for (String s : keys) {
            if(latest==null){
                latest=new SimpleDateFormat("dd/MM/yyyy").parse(s);
            }else{
                //check if current is latest that 'latest'
                Date current = new SimpleDateFormat("dd/MM/yyyy").parse(s);
                if(current.after(latest)){
                    latest = current;
                }
            }
        }

您可以在地图的键上迭代并查找最新的

Set<String> keys = map.keySet();
        Date latest = null;

        for (String s : keys) {
            if(latest==null){
                latest=new SimpleDateFormat("dd/MM/yyyy").parse(s);
            }else{
                //check if current is latest that 'latest'
                Date current = new SimpleDateFormat("dd/MM/yyyy").parse(s);
                if(current.after(latest)){
                    latest = current;
                }
            }
        }

您可以在单个收集操作中分组和搜索max元素。大致如下:

    Comparator<STUP> comparingTransactionDate =
            Comparator.comparing(STUP::getTransactionDate);

    List<STUP> result = rupFeedDC.stream().collect(() -> new ArrayList<STUP>(), (list,  newItem) -> {
        if (!list.isEmpty()) {
            STUP existingItem = list.get(0);
            int comparingExistingItemToNewItem = 
                    comparingTransactionDate.compare(existingItem, newItem);
            if (comparingExistingItemToNewItem < 0) {
                list.clear();
                list.add(newItem);
            } else if (comparingExistingItemToNewItem == 0){
                list.add(newItem);
            }
        }
        else {
            list.add(newItem);
        }
    }, (list1, list2) -> {
        if (list1.isEmpty()) {
            list1.addAll(list2);
        }
        else if (!list2.isEmpty()) {
            STUP left = list1.get(0);
            STUP right = list2.get(0);
            int leftComparedToRight = comparingTransactionDate.compare(left, right);
            if (leftComparedToRight == 0) {
                list1.addAll(list2);
            } else if (leftComparedToRight < 0) {
                list1.clear();
                list1.addAll(list2);
            }
        }
    });

这种方法为您节省了构建完整地图的时间,而查找最新元素实际上并不需要完整地图。如果您有许多STUP元素并希望保存内存,这可能会有所帮助。

您可以在单个收集操作中分组并搜索max元素。大致如下:

    Comparator<STUP> comparingTransactionDate =
            Comparator.comparing(STUP::getTransactionDate);

    List<STUP> result = rupFeedDC.stream().collect(() -> new ArrayList<STUP>(), (list,  newItem) -> {
        if (!list.isEmpty()) {
            STUP existingItem = list.get(0);
            int comparingExistingItemToNewItem = 
                    comparingTransactionDate.compare(existingItem, newItem);
            if (comparingExistingItemToNewItem < 0) {
                list.clear();
                list.add(newItem);
            } else if (comparingExistingItemToNewItem == 0){
                list.add(newItem);
            }
        }
        else {
            list.add(newItem);
        }
    }, (list1, list2) -> {
        if (list1.isEmpty()) {
            list1.addAll(list2);
        }
        else if (!list2.isEmpty()) {
            STUP left = list1.get(0);
            STUP right = list2.get(0);
            int leftComparedToRight = comparingTransactionDate.compare(left, right);
            if (leftComparedToRight == 0) {
                list1.addAll(list2);
            } else if (leftComparedToRight < 0) {
                list1.clear();
                list1.addAll(list2);
            }
        }
    });
    Optional<Entry<LocalDate, List<STUP>>> latest = rupFeedDC.stream()
            .collect(Collectors.groupingBy(rl -> rl.getTransactionDate()
                    .toLocalDateTime()
                    .toLocalDate()))
            .entrySet()
            .stream()
            .max(Comparator.comparing(Map.Entry<LocalDate, List<STUP>>::getKey));
这种方法为您节省了构建完整地图的时间,而查找最新元素实际上并不需要完整地图。如果您有许多STUP元素并希望保存内存,那么这可能会有所帮助

    Optional<Entry<LocalDate, List<STUP>>> latest = rupFeedDC.stream()
            .collect(Collectors.groupingBy(rl -> rl.getTransactionDate()
                    .toLocalDateTime()
                    .toLocalDate()))
            .entrySet()
            .stream()
            .max(Comparator.comparing(Map.Entry<LocalDate, List<STUP>>::getKey));
如果事实证明,将所有对象(从较早日期开始的对象)分组会占用过大的内存,那么以下是如何避免这种情况的建议:

    Optional<LocalDate> latestDate = rupFeedDC.stream()
            .map(STUP::getTransactionDate)
            .max(Comparator.naturalOrder())
            .map(ts -> ts.toLocalDateTime().toLocalDate());
    latestDate.ifPresent(d -> {
        List<STUP> latestList = rupFeedDC.stream()
                .filter(rl -> rl.getTransactionDate().toLocalDateTime()
                                    .toLocalDate()
                                    .equals(d))
                .collect(Collectors.toList());
        // ...
    });
如果可以在STUP类中使用LocalDateTime而不是Timestamp,则更好。时间戳已过期很久,此更改将为原始列表中的每个对象保存转换

如果事实证明,将所有对象(从较早日期开始的对象)分组会占用过大的内存,那么以下是如何避免这种情况的建议:

    Optional<LocalDate> latestDate = rupFeedDC.stream()
            .map(STUP::getTransactionDate)
            .max(Comparator.naturalOrder())
            .map(ts -> ts.toLocalDateTime().toLocalDate());
    latestDate.ifPresent(d -> {
        List<STUP> latestList = rupFeedDC.stream()
                .filter(rl -> rl.getTransactionDate().toLocalDateTime()
                                    .toLocalDate()
                                    .equals(d))
                .collect(Collectors.toList());
        // ...
    });

如果可以在STUP类中使用LocalDateTime而不是Timestamp,则更好。时间戳早已过时,此更改将为原始列表中的每个对象保存一次转换。

当您只对一个组感兴趣时,执行分组操作没有多大意义。由于这些组是由属性确定的,因此您只需查找该属性具有相同值的所有元素

因此,首先,确定该属性的值,即最大时间戳:

TreeMap<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
             .collect(Collectors.groupingBy(STUP::getTransactionDate,
                                            TreeMap::new,
                                            Collectors.toList()));
Timestamp last = timestampListMap.lastKey();
Timestamp latest = rupFeedDC.stream()
    .map(STUP::getTransactionDate)
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));
然后,收集具有该属性值的所有元素

List<STUP> items = rupFeedDC.stream()
    .filter(item -> item.getTransactionDate().equals(latest))
    .collect(Collectors.toList());
您的问题代码表明您希望以日粒度处理日期,尽管它不起作用,您可以使用

LocalDateTime latest = rupFeedDC.stream()
    .map(item -> item.getTransactionDate().toLocalDateTime().truncatedTo(ChronoUnit.DAYS))
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));
List<STUP> items = rupFeedDC.stream()
    .filter(item -> item.getTransactionDate().toLocalDateTime()
                        .truncatedTo(ChronoUnit.DAYS).equals(latest))
    .collect(Collectors.toList());
Map<LocalDateTime, List<STUP>> timestampListMap = Collections.singletonMap(latest, items);

作为旁注,如果您的代码和示例说明都表明您实际上想要最晚的一天,那么说您想要“最晚的一个月”是没有意义的。

当您只对一个组感兴趣时,执行分组操作没有多大意义。由于这些组是由属性确定的,因此您只需查找该属性具有相同值的所有元素

因此,首先,确定该属性的值,即最大时间戳:

TreeMap<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
             .collect(Collectors.groupingBy(STUP::getTransactionDate,
                                            TreeMap::new,
                                            Collectors.toList()));
Timestamp last = timestampListMap.lastKey();
Timestamp latest = rupFeedDC.stream()
    .map(STUP::getTransactionDate)
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));
然后,收集具有该属性值的所有元素

List<STUP> items = rupFeedDC.stream()
    .filter(item -> item.getTransactionDate().equals(latest))
    .collect(Collectors.toList());
您的问题代码表明您希望以日粒度处理日期,尽管它不起作用,您可以使用

LocalDateTime latest = rupFeedDC.stream()
    .map(item -> item.getTransactionDate().toLocalDateTime().truncatedTo(ChronoUnit.DAYS))
    .max(Comparator.naturalOrder())
    .orElseThrow(() -> new IllegalStateException("no entries"));
List<STUP> items = rupFeedDC.stream()
    .filter(item -> item.getTransactionDate().toLocalDateTime()
                        .truncatedTo(ChronoUnit.DAYS).equals(latest))
    .collect(Collectors.toList());
Map<LocalDateTime, List<STUP>> timestampListMap = Collections.singletonMap(latest, items);

作为旁注,如果您的代码和示例说明都表明您实际上想要最晚的一天,那么说您想要“最晚的一个月”是没有意义的。

我已经更改了它,这是我的错误是java.sql.Timestamp类您最初的forEach操作没有效果。它会将时间戳截断为日期,但不会将结果存储回您的STUP对象中。您想要获取的“最近一个月”与仅获取最新日期之间是否存在逻辑差异?显然不是,因为2017年4月23日和2017年4月21日是同一个月,你说你只想要2017年4月23日,最晚的一天。我更改了它,这是我的错误。是的,是java.sql.Timestamp类。你最初的forEach操作没有效果。它会将时间戳截断为日期,但不会将结果存储回您的STUP对象中。您想要获取的“最近一个月”与仅获取最新日期之间是否存在逻辑差异?显然不是,因为2017年4月23日和2017年4月21日是同一个月,你说你只想得到2017年4月23日,最新的dayHolger,在lasst代码片段中,你将每个时间戳转换为LocalDateTime并截断两次。即使你只需要最后一组,这不是比分组更浪费吗?@OleV.V。这两种方法在所需的CPU时间方面都是线性的,但分组的内存占用要高得多,因为它会分配和填充包含每个组(pl)成员的列表
我的答案的最后一个片段仍然只分配一个包含OP感兴趣的元素的列表。Holger,在lasst片段中,您将每个时间戳转换为LocalDateTime并截断两次。即使你只需要最后一组,这不是比分组更浪费吗?@OleV.V。这两种方法在所需的CPU时间方面都是线性的,但分组的内存占用要高得多,因为它分配和填充包含每个组成员的列表,以及包含这些成员的映射,而我的答案的最后一个片段仍然只分配一个包含OP感兴趣的元素的列表。