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

时间:2018-04-09 07:13:08

标签: java java-8 hashmap

我的地图如下:

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

Map<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
    .collect(Collectors.groupingBy(STUP::getTransactionDate));

现在,我希望获得包含最新月份的日期。

例如: 对于地图:

map.put("23/04/2017", someList);
map.put("21/04/2017", someList);
map.put("03/03/2017", someList);
map.put("04/02/2017", someList);
map.put("09/01/2017", someList);

我想只拥有密钥&#34; 23/04/2017&#34;,因为它包含最近一个月。任何人都可以建议我能为它做些什么吗?

5 个答案:

答案 0 :(得分:3)

由于您的密钥是java.sql.Timestamp,因此您可以利用它实现Comparable的事实。修改流管道以生成TreeMap(其中键按升序排序),最后一个键将是最新的时间戳:

TreeMap<Timestamp, List<STUP>> timestampListMap =
    rupFeedDC.stream()
             .collect(Collectors.groupingBy(STUP::getTransactionDate,
                                            TreeMap::new,
                                            Collectors.toList()));
Timestamp last = timestampListMap.lastKey();

答案 1 :(得分:2)

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

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

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

如果您仍然认为需要包含该组的Map,则可以使用

Map<Timestamp, List<STUP>> timestampListMap = Collections.singletonMap(latest, items);

您的问题代码表明您希望以日期粒度处理日期(尽管它不起作用),您可以使用

来实现
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);

作为旁注,如果你想要“最近一个月”,你的代码和你的例子说明你实际上想要最新的 是没有意义的。

答案 2 :(得分:1)

    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)。例如使用:

    latest.ifPresent(e -> {
        LocalDate latestDate = e.getKey();
        List<STUP> latestList = e.getValue();
        // ...
    });

如果事实证明对所有对象(来自早期日期的对象)进行分组的内存占用空间太大,这里建议如何避免这种情况:

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

如果您可以在LocalDateTime课程中使用STUP而不是Timestamp,那就更好了。 Timestamp已过时,此更改将为原始列表中的每个对象保存转化。

答案 3 :(得分:0)

您可以迭代地图的键并找到最新的。

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

答案 4 :(得分:0)

您可以在单个collect操作中对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);
            }
        }
    });

这种方法可以为您节省构建完整的Map<Timestamp, List<STUP>>,这对于找到最新的元素并不是非常需要的。如果您有许多STUP元素并想要保存内存,这可能会有所帮助。