I have a File.txt (represent NewBorn
).
I've created a class NewBorn
that has the following fields: id
, name
, age
.
Then I'm reading the file and parsing it, so I can get a nice output.
From the list of newborn (based on file.txt) I need to get the date on which the most children were born, but I have a problem filtering through that.
That's what I've tried :
public static List<NewBorn> dateInWitchMostChildrenAreBorn(List<NewBorn> newBornList) {
return newBornList.stream()
.filter(newBorn -> newBorn.getBirthdate() // in here I tried to go use = but is not good of course )
//then I want to collect that and count the one that is the most in witch children are born
.collect((Collectors.toSet()));
}
CodePudding user response:
Here, First filtering the null birthdate
, then grouping it by birthdate then collecting it to a Map with birthdate
as key and occurrence as value, then returning the max occurrence birthdate
public static LocalDate dateInWitchMostChildrenAreBorn(List<NewBorn> newBornList) {
return newBornList.stream()
.filter(newBorn -> Objects.nonNull(newBorn.getBirthdate()))
.collect(Collectors.groupingBy(NewBorn::getBirthdate, Collectors.counting()))
.entrySet().stream()
.max(Map.Entry.comparingByValue())
.map(Map.Entry::getKey).orElse(null);
}
CodePudding user response:
There could be multiple dates for which the numbers of children have been born are equal. Therefore, there can be more than one date that corresponds to the maximum number of newborns. Maybe that's why the method listed in the question is meant to return a list.
In order to obtain the List<LocalDate>
containing all dates when number of newborns is maximal, first, we need to create map Map<LocalDate, Long>
(number of newborns by date) by using collector Collectors.groupingBy()
. The function that extracts the birthdate is used as the first argument and Collectors.counting()
, that generates the number of elements mapped to a key, as a downstream collector.
Then we can generate the resulting list in a single pass over the entries of this map with a custom collector that will collect the entries having the highest previously encountered count. If the next entry has a value greater the previous maximum, intermediate results will be cleaned up.
To implement a custom collector, we can utilize the static method of()
defined in the Collector
interface.
ArrayDeque
is used as mutable container of the collector.
The finisher function creates a stream over the resulting queue, which extracts date objects from the entries and collect them into a list.
public static List<LocalDate> dateInWitchMostChildrenAreBorn(List<NewBorn> newBornList) {
return newBornList.stream()
.collect(Collectors.groupingBy(NewBorn::getBirthdate,
Collectors.counting())) // Map<LocalDate, Long> - number of newborns by date
.entrySet().stream()
.collect(Collector.of(
ArrayDeque::new, // supplier
(Queue<Map.Entry<LocalDate, Long>> queue,
Map.Entry<LocalDate, Long> next) -> { // accumulator
if (!queue.isEmpty() && queue.element().getValue() < next.getValue()) queue.clear();
if (queue.isEmpty() || queue.element().getValue().equals(next.getValue())) queue.add(next);
},
(Queue<Map.Entry<LocalDate, Long>> left,
Queue<Map.Entry<LocalDate, Long>> right) -> { // combiner
if (left.isEmpty()) return right;
if (right.isEmpty()) return left;
if (left.element().getValue() < right.element().getValue()) return right;
if (left.element().getValue() > right.element().getValue()) return left;
else {left.addAll(right); return left;}
},
(Queue<Map.Entry<LocalDate, Long>> queue) -> // finisher
queue.stream().map(Map.Entry::getKey).toList()
));
}
main()
- demo
public static void main(String[] args) {
List<NewBorn> newBorns =
List.of(new NewBorn(LocalDate.of(2021, 1, 5)),
new NewBorn(LocalDate.of(2021, 3, 8)),
new NewBorn(LocalDate.of(2021, 3, 8)),
new NewBorn(LocalDate.of(2021, 12, 10)),
new NewBorn(LocalDate.of(2021, 12, 10)),
new NewBorn(LocalDate.of(2021, 1, 5)),
new NewBorn(LocalDate.of(2021, 5, 25)),
new NewBorn(LocalDate.of(2021, 7, 12)));
System.out.println(dateInWitchMostChildrenAreBorn(newBorns));
}
Output (expected : three dates on which the number of newborns is 2
)
[2021-12-10, 2021-03-08, 2021-01-05]