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感兴趣的元素的列表。