So here is the situation: I need to register people's vote for certain dates. In short, a date is proposed and people vote for the date they want.
The data structure is the following:
private HashMap<LocalDateTime, Set<Vote>> votes;
A vote is:
public class Vote {
private String name;
private VoteType vote;
public Vote(String name, VoteType vote) {
super();
this.name = name;
this.vote = vote;
}
}
Where VoteType is just an enum:
public enum VoteType {YES, NO, MAYBE}
Now I already made a stream that returns the amount of votes for the availability (VoteType):
public Map<LocalDateTime, Integer> voteCount(VoteType targetVote) {
return this.votes.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, e -> new Integer(
e.getValue().stream().filter(v -> v.getVote() == targetVote).collect(Collectors.toList()).size())));
}
So my question is: How can I get, using Java Streams, the date that got the most 'YES'.
/* Returns the date that got the most 'YES' votes */
public LocalDateTime winningDate() {
// TODO
}
Thank you for the help!
So my question is: How can I get, using Java Streams, the date that got the most 'YES'.
This is going to be a lengthy one...
Stream<LocalDateTime>
so we can later group by date applying a counting
downstream collector to get the number of votes on that specific date and we can accomplish this structure via flatMap
.YES
YES
votes on that specific date.entrySet
and find the max
date by voteCode:
/* Returns the date that got the most 'YES' votes */
public Optional<LocalDateTime> getWinningDate() {
return votes.entrySet() // Set<Entry<LocaleDateTime, Set<Vote>>
.stream() // Stream<Entry<LocaleDateTime, Set<Vote>>
.flatMap(e -> e.getValue().stream().filter(a -> a.getVote() == VoteType.YES)
.map(x -> e.getKey())) // Stream<LocalDateTime>
.collect(groupingBy(Function.identity(), counting())) // Map<LocaleDateTime, Long>
.entrySet() // Set<Entry<LocaleDateTime, Long>>
.stream() // Stream<Entry<LocaleDateTime, Long>>
.max(Comparator.comparingLong(Map.Entry::getValue)) // Optional<Entry<LocaleDateTime, Long>>
.map(Map.Entry::getKey); // Optional<LocalDateTime>
}
Optional<LocaleDateTime>
, I could have returned
.map(Map.Entry::getKey).orElse(null)
thus you've be able to maintain your current method return type of LocalDateTime
but that just feels bad and so
I've decided to defer the decision upon what to do in the "no value
case" to the client.getWinningDate
to enhance readability.As for dealing with Optional<T>
, in your case, if you want to have a null
value in the case of getWinningDate
returning an empty Optional, you can unwrap it safely as:
LocalDateTime winningDate = getWinningDate().orElse(null);
or if you want to provide a default date:
LocalDateTime winningDate = getWinningDate().orElse(defaultDate);
or if you're sure there will always be a result then simply call get()
.
LocalDateTime winningDate = getWinningDate().get();
etc..
You can do it this way:
private LocalDateTime winningDate(Map<LocalDateTime, Integer> mapGroup) {
Integer max = mapGroup
.values().stream()
.max(Comparator.naturalOrder())
.get();
return mapGroup
.entrySet()
.stream()
.filter(e -> e.getValue().equals(max))
.map(Map.Entry::getKey)
.findFirst().orElse(null);
}
Use your first method which counts up the YES votes, returns a map of the yes counts which is passed into the winning date method:
/* Returns the date that got the most 'YES' votes */
public LocalDateTime winningDate(Map<LocalDateTime, Integer> yesVotes) {
return yesVotes.entrySet().stream().max(Map.Entry.comparingByValue()).get().getKey();
}
I can't help but thinking this was the intention here, but what do I know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With