使用 Stream API 统计数据
Using Stream API to count stats
我有以下代表小吃店的模型
SnackBarStat - 这有预订的开始日期、预订的客户数量和天数(客户可以设置开始日期并说出他们想要多少天table)
public class SnackBarStat {
LocalDate startDate;
int numberOfDays;
int customers;
}
现在给出此类统计信息的列表,我试图找出每个日期小吃店有多少顾客
例如如果输入是
Start date 13-9-2021, Customers: 2 , numberOfDays: 3
Start date 12-9-2021, Customers: 3 , numberOfDays: 2
Start date 13-9-2021, Customers: 1 , numberOfDays: 1
预期输出为
{2021-09-12=3, 2021-09-13=6, 2021-09-14=2, 2021-09-15=2}
到目前为止我已经尝试过什么。
我创建了一个简单的逻辑来遍历每个开始日期,根据 numberOfDays 扩展日期,然后将每个日期添加到地图中,并在该日期对客户求和
public class SnackBarOccupanceTest {
public static void main(String args[]){
SnackBarStat snackBarStat1 = new SnackBarStat();
snackBarStat1.setStartDate(LocalDate.of(2021, 9, 13));
snackBarStat1.setCustomers(2);
snackBarStat1.setNumberOfDays(3);
SnackBarStat snackBarStat2 = new SnackBarStat();
snackBarStat2.setStartDate(LocalDate.of(2021, 9, 12));
snackBarStat2.setCustomers(3);
snackBarStat2.setNumberOfDays(2);
SnackBarStat snackBarStat3 = new SnackBarStat();
snackBarStat3.setStartDate(LocalDate.of(2021, 9, 13));
snackBarStat3.setCustomers(1);
snackBarStat3.setNumberOfDays(1);
Map<LocalDate, Integer> occupancePerDate = new HashMap<>();
List<SnackBarStat> snackBarStats = List.of(snackBarStat1, snackBarStat2, snackBarStat3);
for(SnackBarStat snackBarStat:snackBarStats){
var expandedDates = expandDates(snackBarStat.getStartDate(), snackBarStat.getNumberOfDays());
for(LocalDate eachDate : expandedDates){
if(occupancePerDate.get(eachDate) != null){
var existingCustomers = occupancePerDate.get(eachDate);
occupancePerDate.put(eachDate, existingCustomers + snackBarStat.getCustomers());
}else{
occupancePerDate.put(eachDate, snackBarStat.getCustomers());
}
}
}
System.out.println(occupancePerDate);
}
public static List<LocalDate> expandDates (LocalDate startDate, int numberOfDays){
List<LocalDate> dateRanges = new ArrayList<>();
for(int i = 0; i < numberOfDays; i++){
dateRanges.add(startDate.plusDays(i));
}
return dateRanges;
}
}
此代码有效。我想知道流 api 是否有更短的方法来做同样的事情。
请注意,该代码仅用于演示目的,我在实际代码中使用了更好的代码实践。
您可以使用 flatMap
来“展开”日期,然后您可以使用 groupingBy
来对展开的日期进行分组:
Map<LocalDate, Integer> occupancePerDate = snackBarStats.stream()
.flatMap(x -> // expand the dates
IntStream.range(0, x.getNumberOfDays())
// for each date, we create a new SnackBarStat with
// that date, numberOfDays=1, and the same number of customers
.mapToObj(n -> new SnackBarStat(x.getStartDate().plusDays(n), 1, x.getCustomers()))
).collect(Collectors.groupingBy(
SnackBarStat::getStartDate, // group by start date
Collectors.summingInt(SnackBarStat::getCustomers) // for each group, sum the customers
));
虽然这更短,但请注意它可能比您的循环慢。
我有以下代表小吃店的模型 SnackBarStat - 这有预订的开始日期、预订的客户数量和天数(客户可以设置开始日期并说出他们想要多少天table)
public class SnackBarStat {
LocalDate startDate;
int numberOfDays;
int customers;
}
现在给出此类统计信息的列表,我试图找出每个日期小吃店有多少顾客
例如如果输入是
Start date 13-9-2021, Customers: 2 , numberOfDays: 3
Start date 12-9-2021, Customers: 3 , numberOfDays: 2
Start date 13-9-2021, Customers: 1 , numberOfDays: 1
预期输出为
{2021-09-12=3, 2021-09-13=6, 2021-09-14=2, 2021-09-15=2}
到目前为止我已经尝试过什么。 我创建了一个简单的逻辑来遍历每个开始日期,根据 numberOfDays 扩展日期,然后将每个日期添加到地图中,并在该日期对客户求和
public class SnackBarOccupanceTest {
public static void main(String args[]){
SnackBarStat snackBarStat1 = new SnackBarStat();
snackBarStat1.setStartDate(LocalDate.of(2021, 9, 13));
snackBarStat1.setCustomers(2);
snackBarStat1.setNumberOfDays(3);
SnackBarStat snackBarStat2 = new SnackBarStat();
snackBarStat2.setStartDate(LocalDate.of(2021, 9, 12));
snackBarStat2.setCustomers(3);
snackBarStat2.setNumberOfDays(2);
SnackBarStat snackBarStat3 = new SnackBarStat();
snackBarStat3.setStartDate(LocalDate.of(2021, 9, 13));
snackBarStat3.setCustomers(1);
snackBarStat3.setNumberOfDays(1);
Map<LocalDate, Integer> occupancePerDate = new HashMap<>();
List<SnackBarStat> snackBarStats = List.of(snackBarStat1, snackBarStat2, snackBarStat3);
for(SnackBarStat snackBarStat:snackBarStats){
var expandedDates = expandDates(snackBarStat.getStartDate(), snackBarStat.getNumberOfDays());
for(LocalDate eachDate : expandedDates){
if(occupancePerDate.get(eachDate) != null){
var existingCustomers = occupancePerDate.get(eachDate);
occupancePerDate.put(eachDate, existingCustomers + snackBarStat.getCustomers());
}else{
occupancePerDate.put(eachDate, snackBarStat.getCustomers());
}
}
}
System.out.println(occupancePerDate);
}
public static List<LocalDate> expandDates (LocalDate startDate, int numberOfDays){
List<LocalDate> dateRanges = new ArrayList<>();
for(int i = 0; i < numberOfDays; i++){
dateRanges.add(startDate.plusDays(i));
}
return dateRanges;
}
}
此代码有效。我想知道流 api 是否有更短的方法来做同样的事情。 请注意,该代码仅用于演示目的,我在实际代码中使用了更好的代码实践。
您可以使用 flatMap
来“展开”日期,然后您可以使用 groupingBy
来对展开的日期进行分组:
Map<LocalDate, Integer> occupancePerDate = snackBarStats.stream()
.flatMap(x -> // expand the dates
IntStream.range(0, x.getNumberOfDays())
// for each date, we create a new SnackBarStat with
// that date, numberOfDays=1, and the same number of customers
.mapToObj(n -> new SnackBarStat(x.getStartDate().plusDays(n), 1, x.getCustomers()))
).collect(Collectors.groupingBy(
SnackBarStat::getStartDate, // group by start date
Collectors.summingInt(SnackBarStat::getCustomers) // for each group, sum the customers
));
虽然这更短,但请注意它可能比您的循环慢。