import java.time.YearMonth;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* 计算同比
*/
public class YearOverYearComparison {
/**
* 直接从 VO 对象列表计算同比
* @param currentData 当年数据列表
* @param previousData 去年数据列表
* @param keyExtractor 获取日期字段的函数
* @param valueExtractor 获取数值字段的函数
* @return 同比结果 Map<yyyy-MM, growthRate>
* 使用demo:
* // 计算同比
* Map<String, Double> yearOverYearResult2 = YearOverYearComparison.calculateYearOverYear(
* currentData, previousData,
* MonthStatisticsVo::getYm,
* MonthStatisticsVo::getAvgNum);
*/
public static <T> Map<String, Double> calculateYearOverYear(
List<T> currentData,
List<T> previousData,
Function<T, String> keyExtractor,
Function<T, Double> valueExtractor) {
Map<String, Double> currentMap = currentData.stream()
.collect(Collectors.toMap(keyExtractor, valueExtractor));
Map<String, Double> previousMap = previousData.stream()
.collect(Collectors.toMap(keyExtractor, valueExtractor));
return calculateYearOverYear(
Collections.singletonList(currentMap),
Collections.singletonList(previousMap)
);
}
/**
* 计算两年数据的同比
* @param currentData 当年数据列表 Map<yyyy-MM, value>
* @param previousData 去年数据列表 Map<yyyy-MM, value>
* @return 同比结果 Map<yyyy-MM, growthRate>
*/
public static Map<String, Double> calculateYearOverYear(
List<Map<String, Double>> currentData,
List<Map<String, Double>> previousData) {
Map<String, Double> currentMap = convertToMap(currentData);
Map<String, Double> previousMap = convertToMap(previousData);
Map<String, Double> result = new HashMap<>();
for (Map.Entry<String, Double> entry : currentMap.entrySet()) {
String monthKey = entry.getKey();
Double currentValue = entry.getValue();
// 获取去年同期数据
String previousMonthKey = getPreviousYearMonth(monthKey);
Double previousValue = previousMap.get(previousMonthKey);
if (previousValue != null && previousValue != 0) {
// 计算同比增长率
double growthRate = (currentValue - previousValue) / previousValue;
result.put(monthKey, growthRate);
}
}
return result;
}
/**
* 将List<Map>转换为Map
*/
private static Map<String, Double> convertToMap(List<Map<String, Double>> dataList) {
Map<String, Double> map = new HashMap<>();
for (Map<String, Double> data : dataList) {
map.putAll(data);
}
return map;
}
/**
* 获取去年同期月份
*/
private static String getPreviousYearMonth(String month) {
try {
YearMonth yearMonth = YearMonth.parse(month);
YearMonth previous = yearMonth.minusYears(1);
return previous.toString();
} catch (Exception e) {
return null;
}
}
public static void main(String[] args) {
// 示例数据
List<Map<String, Double>> currentYearData = Arrays.asList(
Map.of("2024-01", 100.0),
Map.of("2024-02", 120.0)
);
List<Map<String, Double>> previousYearData = Arrays.asList(
Map.of("2023-01", 90.0),
Map.of("2023-02", 100.0),
Map.of("2023-03", 95.0)
);
// 计算同比
Map<String, Double> yearOverYearResult = YearOverYearComparison.calculateYearOverYear(
currentYearData, previousYearData);
// 输出结果
yearOverYearResult.forEach((month, rate) ->
System.out.println(month + " 同比增长: " + String.format("%.2f%%", rate * 100)));
List<MonthStatisticsVo> currentData = Arrays.asList(
new MonthStatisticsVo("2024-01", 100.0),
new MonthStatisticsVo("2024-02", 120.0)
);
List<MonthStatisticsVo> previousData = Arrays.asList(
new MonthStatisticsVo("2023-01", 90.0),
new MonthStatisticsVo("2023-02", 100.0),
new MonthStatisticsVo("2023-03", 95.0)
);
// 计算同比
Map<String, Double> yearOverYearResult2 = YearOverYearComparison.calculateYearOverYear(
currentData, previousData,
MonthStatisticsVo::getYm,
MonthStatisticsVo::getAvgNum);
// 输出结果
yearOverYearResult2.forEach((month, rate) ->
System.out.println(month + " 同比增长: " + String.format("%.2f%%", rate * 100)));
}
}
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
@AllArgsConstructor
@Data
public class MonthStatisticsVo {
@Schema(description = "年月")
private String ym;
@Schema(description = "平均数")
private Double avgNum;
}