|
|
@ -22,43 +22,51 @@ public class LineDataHourAggregator { |
|
|
public static void aggregateByHour(LineData lineData) { |
|
|
public static void aggregateByHour(LineData lineData) { |
|
|
|
|
|
|
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> yData = lineData.getYData(); |
|
|
Map<String, List<Object>> yDataMap = lineData.getYData(); |
|
|
|
|
|
|
|
|
if (xData == null || yData == null || xData.size() != yData.size()) { |
|
|
if (xData == null || yDataMap == null || yDataMap.isEmpty()) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// hour -> List<Double>
|
|
|
// hour -> index
|
|
|
Map<String, List<Double>> hourMap = new TreeMap<>(); |
|
|
Map<String, Integer> hourIndexMap = new TreeMap<>(); |
|
|
|
|
|
Map<String, Map<String, List<Double>>> hourValueMap = new TreeMap<>(); |
|
|
|
|
|
|
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
String timeStr = String.valueOf(xData.get(i)); |
|
|
String timeStr = String.valueOf(xData.get(i)); |
|
|
Object yVal = yData.get(i); |
|
|
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT); |
|
|
|
|
|
String hourKey = time.format(HOUR_FMT); |
|
|
|
|
|
|
|
|
|
|
|
hourIndexMap.putIfAbsent(hourKey, hourIndexMap.size()); |
|
|
|
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<Object>> entry : yDataMap.entrySet()) { |
|
|
|
|
|
Object yVal = entry.getValue().get(i); |
|
|
if (yVal == null) { |
|
|
if (yVal == null) { |
|
|
continue; |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT); |
|
|
hourValueMap |
|
|
String hourKey = time.format(HOUR_FMT); |
|
|
.computeIfAbsent(hourKey, k -> new HashMap<>()) |
|
|
|
|
|
.computeIfAbsent(entry.getKey(), k -> new ArrayList<>()) |
|
|
hourMap.computeIfAbsent(hourKey, k -> new ArrayList<>()).add(Double.parseDouble(String.valueOf(yVal))); |
|
|
.add(Double.parseDouble(String.valueOf(yVal))); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 重新构建 xData / yData
|
|
|
|
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newY = new ArrayList<>(); |
|
|
Map<String, List<Object>> newY = new HashMap<>(); |
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<Double>> entry : hourMap.entrySet()) { |
|
|
for (String hourKey : hourIndexMap.keySet()) { |
|
|
newX.add(entry.getKey()); |
|
|
newX.add(hourKey); |
|
|
|
|
|
|
|
|
double avg = entry.getValue() |
|
|
Map<String, List<Double>> seriesMap = hourValueMap.get(hourKey); |
|
|
.stream() |
|
|
if (seriesMap == null) { |
|
|
.mapToDouble(Double::doubleValue) |
|
|
continue; |
|
|
.average() |
|
|
} |
|
|
.orElse(0); |
|
|
|
|
|
|
|
|
|
|
|
newY.add(avg); |
|
|
for (Map.Entry<String, List<Double>> e : seriesMap.entrySet()) { |
|
|
|
|
|
double avg = e.getValue().stream().mapToDouble(Double::doubleValue).average().orElse(0); |
|
|
|
|
|
newY.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(avg); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
lineData.setXData(newX); |
|
|
lineData.setXData(newX); |
|
|
@ -72,38 +80,42 @@ public class LineDataHourAggregator { |
|
|
public static void fillTodayHalfHourPointsJST(LineData lineData) { |
|
|
public static void fillTodayHalfHourPointsJST(LineData lineData) { |
|
|
|
|
|
|
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> yData = lineData.getYData(); |
|
|
Map<String, List<Object>> yDataMap = lineData.getYData(); |
|
|
|
|
|
|
|
|
if (xData == null || yData == null || xData.size() != yData.size()) { |
|
|
if (xData == null || yDataMap == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
ZoneId JST = ZoneId.of("Asia/Tokyo"); |
|
|
ZoneId JST = ZoneId.of("Asia/Tokyo"); |
|
|
|
|
|
LocalDate todayJst = LocalDate.now(JST); |
|
|
|
|
|
LocalDateTime start = todayJst.atStartOfDay(); |
|
|
|
|
|
|
|
|
|
|
|
// 原数据转 Map:time -> series -> value
|
|
|
|
|
|
Map<String, Map<String, Object>> valueMap = new HashMap<>(); |
|
|
|
|
|
|
|
|
// 现有数据转 Map
|
|
|
|
|
|
Map<String, Double> valueMap = new HashMap<>(); |
|
|
|
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
valueMap.put( |
|
|
String time = String.valueOf(xData.get(i)); |
|
|
String.valueOf(xData.get(i)), |
|
|
for (Map.Entry<String, List<Object>> e : yDataMap.entrySet()) { |
|
|
Double.parseDouble(String.valueOf(yData.get(i))) |
|
|
valueMap |
|
|
); |
|
|
.computeIfAbsent(time, k -> new HashMap<>()) |
|
|
|
|
|
.put(e.getKey(), e.getValue().get(i)); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 日本“今天”
|
|
|
|
|
|
LocalDate todayJst = LocalDate.now(JST); |
|
|
|
|
|
|
|
|
|
|
|
List<Object> newX = new ArrayList<>(48); |
|
|
List<Object> newX = new ArrayList<>(48); |
|
|
List<Object> newY = new ArrayList<>(48); |
|
|
Map<String, List<Object>> newY = new HashMap<>(); |
|
|
|
|
|
|
|
|
// 日本当天 00:00
|
|
|
|
|
|
LocalDateTime start = todayJst.atStartOfDay(); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < 48; i++) { |
|
|
for (int i = 0; i < 48; i++) { |
|
|
LocalDateTime timePoint = start.plusMinutes(i * 30); |
|
|
LocalDateTime t = start.plusMinutes(i * 30); |
|
|
String key = timePoint.format(INPUT_FMT); |
|
|
String key = t.format(INPUT_FMT); |
|
|
|
|
|
|
|
|
newX.add(key); |
|
|
newX.add(key); |
|
|
newY.add(valueMap.getOrDefault(key, null)); |
|
|
|
|
|
|
|
|
Map<String, Object> seriesValues = valueMap.get(key); |
|
|
|
|
|
for (String series : yDataMap.keySet()) { |
|
|
|
|
|
newY |
|
|
|
|
|
.computeIfAbsent(series, k -> new ArrayList<>()) |
|
|
|
|
|
.add(seriesValues == null ? null : seriesValues.get(series)); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
lineData.setXData(newX); |
|
|
lineData.setXData(newX); |
|
|
@ -119,54 +131,42 @@ public class LineDataHourAggregator { |
|
|
public static void aggregateAverageByHalfHour(LineData lineData) { |
|
|
public static void aggregateAverageByHalfHour(LineData lineData) { |
|
|
|
|
|
|
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> yData = lineData.getYData(); |
|
|
Map<String, List<Object>> yDataMap = lineData.getYData(); |
|
|
|
|
|
|
|
|
if (xData == null || yData == null || xData.size() != yData.size()) { |
|
|
if (xData == null || yDataMap == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// halfHour -> List<Double>
|
|
|
Map<String, Map<String, List<Double>>> halfHourMap = new TreeMap<>(); |
|
|
Map<String, List<Double>> halfHourMap = new TreeMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
String timeStr = String.valueOf(xData.get(i)); |
|
|
LocalDateTime time = LocalDateTime.parse(String.valueOf(xData.get(i)), INPUT_FMT); |
|
|
Object yVal = yData.get(i); |
|
|
|
|
|
|
|
|
|
|
|
if (yVal == null) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT); |
|
|
int minute = time.getMinute() < 30 ? 0 : 30; |
|
|
|
|
|
LocalDateTime halfHourTime = time.withMinute(minute).withSecond(0).withNano(0); |
|
|
|
|
|
String key = halfHourTime.format(INPUT_FMT); |
|
|
|
|
|
|
|
|
int minute = time.getMinute(); |
|
|
for (Map.Entry<String, List<Object>> e : yDataMap.entrySet()) { |
|
|
int halfHourMinute = minute < 30 ? 0 : 30; |
|
|
Object yVal = e.getValue().get(i); |
|
|
|
|
|
if (yVal == null) continue; |
|
|
LocalDateTime halfHourTime = time |
|
|
|
|
|
.withMinute(halfHourMinute) |
|
|
|
|
|
.withSecond(0) |
|
|
|
|
|
.withNano(0); |
|
|
|
|
|
|
|
|
|
|
|
String halfHourKey = halfHourTime.format(INPUT_FMT); |
|
|
|
|
|
|
|
|
|
|
|
halfHourMap |
|
|
halfHourMap |
|
|
.computeIfAbsent(halfHourKey, k -> new ArrayList<>()) |
|
|
.computeIfAbsent(key, k -> new HashMap<>()) |
|
|
|
|
|
.computeIfAbsent(e.getKey(), k -> new ArrayList<>()) |
|
|
.add(Double.parseDouble(String.valueOf(yVal))); |
|
|
.add(Double.parseDouble(String.valueOf(yVal))); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
// 重新构建 xData / yData
|
|
|
|
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newY = new ArrayList<>(); |
|
|
Map<String, List<Object>> newY = new HashMap<>(); |
|
|
|
|
|
|
|
|
for (Map.Entry<String, List<Double>> entry : halfHourMap.entrySet()) { |
|
|
for (Map.Entry<String, Map<String, List<Double>>> entry : halfHourMap.entrySet()) { |
|
|
newX.add(entry.getKey()); |
|
|
newX.add(entry.getKey()); |
|
|
|
|
|
|
|
|
double avg = entry.getValue() |
|
|
for (Map.Entry<String, List<Double>> e : entry.getValue().entrySet()) { |
|
|
.stream() |
|
|
double avg = e.getValue().stream().mapToDouble(Double::doubleValue).average().orElse(0); |
|
|
.mapToDouble(Double::doubleValue) |
|
|
newY.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(avg); |
|
|
.average() |
|
|
} |
|
|
.orElse(0); |
|
|
|
|
|
|
|
|
|
|
|
newY.add(avg); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
lineData.setXData(newX); |
|
|
lineData.setXData(newX); |
|
|
@ -180,49 +180,40 @@ public class LineDataHourAggregator { |
|
|
public static void aggregateLastByHalfHour(LineData lineData) { |
|
|
public static void aggregateLastByHalfHour(LineData lineData) { |
|
|
|
|
|
|
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> xData = lineData.getXData(); |
|
|
List<Object> yData = lineData.getYData(); |
|
|
Map<String, List<Object>> yDataMap = lineData.getYData(); |
|
|
|
|
|
|
|
|
if (xData == null || yData == null || xData.size() != yData.size()) { |
|
|
if (xData == null || yDataMap == null) { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// halfHour -> lastValue
|
|
|
Map<String, Map<String, Object>> halfHourLastMap = new TreeMap<>(); |
|
|
Map<String, Double> halfHourLastMap = new TreeMap<>(); |
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
for (int i = 0; i < xData.size(); i++) { |
|
|
String timeStr = String.valueOf(xData.get(i)); |
|
|
LocalDateTime time = LocalDateTime.parse(String.valueOf(xData.get(i)), INPUT_FMT); |
|
|
Object yVal = yData.get(i); |
|
|
|
|
|
|
|
|
|
|
|
if (yVal == null) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LocalDateTime time = LocalDateTime.parse(timeStr, INPUT_FMT); |
|
|
int minute = time.getMinute() < 30 ? 0 : 30; |
|
|
|
|
|
LocalDateTime halfHourTime = time.withMinute(minute).withSecond(0).withNano(0); |
|
|
|
|
|
String key = halfHourTime.format(INPUT_FMT); |
|
|
|
|
|
|
|
|
int minute = time.getMinute(); |
|
|
for (Map.Entry<String, List<Object>> e : yDataMap.entrySet()) { |
|
|
int halfHourMinute = minute < 30 ? 0 : 30; |
|
|
Object yVal = e.getValue().get(i); |
|
|
|
|
|
if (yVal == null) continue; |
|
|
|
|
|
|
|
|
LocalDateTime halfHourTime = time |
|
|
halfHourLastMap |
|
|
.withMinute(halfHourMinute) |
|
|
.computeIfAbsent(key, k -> new HashMap<>()) |
|
|
.withSecond(0) |
|
|
.put(e.getKey(), yVal); |
|
|
.withNano(0); |
|
|
} |
|
|
|
|
|
|
|
|
String halfHourKey = halfHourTime.format(INPUT_FMT); |
|
|
|
|
|
|
|
|
|
|
|
// 同一个半小时,后面的会覆盖前面的 → 自然就是“最后一条”
|
|
|
|
|
|
halfHourLastMap.put( |
|
|
|
|
|
halfHourKey, |
|
|
|
|
|
Double.parseDouble(String.valueOf(yVal)) |
|
|
|
|
|
); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 重新构建 xData / yData
|
|
|
|
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newX = new ArrayList<>(); |
|
|
List<Object> newY = new ArrayList<>(); |
|
|
Map<String, List<Object>> newY = new HashMap<>(); |
|
|
|
|
|
|
|
|
for (Map.Entry<String, Double> entry : halfHourLastMap.entrySet()) { |
|
|
for (Map.Entry<String, Map<String, Object>> entry : halfHourLastMap.entrySet()) { |
|
|
newX.add(entry.getKey()); |
|
|
newX.add(entry.getKey()); |
|
|
newY.add(entry.getValue()); |
|
|
|
|
|
|
|
|
for (Map.Entry<String, Object> e : entry.getValue().entrySet()) { |
|
|
|
|
|
newY.computeIfAbsent(e.getKey(), k -> new ArrayList<>()).add(e.getValue()); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
lineData.setXData(newX); |
|
|
lineData.setXData(newX); |
|
|
|