问题
I have a list of activities(Activity) and I want to determine a data structure of the form Map(String, DateTime)
(not Duration or Period; DateTime
it's a must) that maps. For each activity the total duration computed over the monitoring period.
The class Activity has: activityLabel(String)
, startTime(DateTime)
, endTime(DateTime)
. I use joda
time.
This is what I have done:
Map<String, DateTime> durations = activities.stream().collect(Collectors.toMap(
it -> it.activityLabel,
it ->new DateTime(0,0,0,0,0,0)
//,DateTime::plus
));
I guess I should use DateTime plus(ReadablePeriod period) or DateTime plus(ReadableDuration duration) , but I don't know how to send a parameter of type Duration or Period to the method reference.
How can I achieve this result?
EDIT: For the input:
2011-12-03 01:00:00 2011-12-03 9:00:00 Sleeping
2011-12-04 03:00:00 2011-12-04 10:30:00 Sleeping
I should have the output: Sleeping 0-0-0 15:30:00 (years,months,days,hours,minutes,seconds)
回答1:
The code (using a Period) would look like this:
Map<String, Period> map = activities.stream()
.collect(Collectors.toMap(Activity::activityLabel, ac -> new Period(ac.getStartTime(), ac.getEndTime()),
(left, right) -> left.plus(right)));
If you really want to output that Period
as a String, you need PeriodFormatter
.
private static PeriodFormatter periodFormatter() {
return new PeriodFormatterBuilder()
.printZeroAlways()
.minimumPrintedDigits(2)
.appendYears().appendSeparator("-")
.appendMonths().appendSeparator("-")
.appendDays().appendLiteral(" ")
.appendHours().appendSeparator(":")
.appendMinutes().appendSeparator(":")
.appendSeconds().toFormatter();
}
And then your code would look more like this:
Map<String, String> map = activities.stream()
.collect(Collectors.collectingAndThen(
Collectors.toMap(
Activity::getLabel,
ac -> new Period(ac.getStartTime(), ac.getEndTime()),
Period::plus),
m -> m.entrySet().stream().collect(Collectors.toMap(
Entry::getKey,
e -> e.getValue().toString(periodFormatter)))));
System.out.println(map); // {Sleeping=00-00-00 15:30:00
回答2:
As you have mentioned in comment that you really need is a DateTime
not a Period
.
Since the DateTime has no api for DateTime.plus(DateTime)
/DateTime.minus(DateTime)
, but you can plus / minus a Period
on a DateTime
, then you need a DateTime
to start, and the code using Collectors api is replacing toMap
with groupingBy
which is more efficiently and expressiveness for doing the task in your case:
DateTime start = DateTime.now();
Map<String, DateTime> result = list.stream().collect(Collectors.groupingBy(
it -> it.activityLabel,
Collectors.mapping(
it -> new Period(it.startTime, it.endTime),
// the important section is here:
// 1. merge all of periods by using reducing
// 2. convert a Period to a DateTime by collectingAndThen
Collectors.collectingAndThen(
Collectors.reducing(Period.ZERO, Period::plus),
start::plus
)
)
));
来源:https://stackoverflow.com/questions/44097658/how-to-send-parameters-to-a-reference-method-in-a-stream-java-8