Reputation: 479
I have a map as follows:
rupFeedDC.forEach(rl -> rl.getTransactionDate()
.toLocalDateTime()
.truncatedTo(ChronoUnit.DAYS));
Map<Timestamp, List<STUP>> timestampListMap =
rupFeedDC.stream()
.collect(Collectors.groupingBy(STUP::getTransactionDate));
Now, I want to get date which contains the latest month.
For example: for the map:
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);
I want to have only the key "23/04/2017", because it consists of the latest month. Can anyone please suggest me what can I do for it?
Upvotes: 1
Views: 1184
Reputation: 86324
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));
This will give you just the map entry for the latest date (or an empty Optional
in case the list was empty). Use for example like this:
latest.ifPresent(e -> {
LocalDate latestDate = e.getKey();
List<STUP> latestList = e.getValue();
// ...
});
If it turns out that grouping all objects (the ones from earlier dates too) has too big of a memory footprint, here’s a suggestion for how to avoid that:
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());
// ...
});
Better still if you could use LocalDateTime
in your STUP
class instead of Timestamp
. The Timestamp
is long outdated, and this change would save a conversion for each object in your original list.
Upvotes: 1
Reputation: 298389
There is not much sense in performing a grouping operation when you are interested in just one group. Since these groups are determined by a property, you are just looking for all elements having the same value for that property.
So first, determine the value of that property, i.e. the maximum timestamp:
Timestamp latest = rupFeedDC.stream()
.map(STUP::getTransactionDate)
.max(Comparator.naturalOrder())
.orElseThrow(() -> new IllegalStateException("no entries"));
Then, collect all elements having that property value
List<STUP> items = rupFeedDC.stream()
.filter(item -> item.getTransactionDate().equals(latest))
.collect(Collectors.toList());
If you still think you need a Map
containing that one group, you can use
Map<Timestamp, List<STUP>> timestampListMap = Collections.singletonMap(latest, items);
Your question’s code suggests that you want to process the dates at day granularity (though it’s not working), which you can achieve with
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);
As a side note, it makes no sense to say that you want “the latest month” when both, your code and your explanation by example indicate that you actually want the latest day.
Upvotes: 2
Reputation: 43689
You can group and search for max element in a single collect
operation. Something along the lines:
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);
}
}
});
This approach saves you the construction of the complete Map<Timestamp, List<STUP>>
which isn't really needed to find the latest element. It might be helpful if you have many STUP
elements and want to save the memory.
Upvotes: 0
Reputation: 1195
You can iterate over the keys of the map and find the latest.
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;
}
}
}
Upvotes: 0
Reputation: 393936
Since your key is a java.sql.Timestamp
, you can take advantage of the fact that it implements Comparable
. Modify your stream pipeline to generate a TreeMap
(in which the keys are sorted in ascending order), and the last key will be the latest timestamp:
TreeMap<Timestamp, List<STUP>> timestampListMap =
rupFeedDC.stream()
.collect(Collectors.groupingBy(STUP::getTransactionDate,
TreeMap::new,
Collectors.toList()));
Timestamp last = timestampListMap.lastKey();
Upvotes: 3