日拱一卒:时间统计图之坐标拾取优化

2023-02-01  本文已影响0人  Tinyspot

练习:统计当天时间段内的值
横坐标值是连续有间隔的时间段(从当前时间所在的时间段开始)
纵坐标是当前时间段的累加值

分析:从当前时间,最主要的是设置 totalIndex
主要代码逻辑

// 从当前时间所在的时间段开始
long startTime = Long.parseLong(String.valueOf(datas.get(0).get(MINUTES)));
long totalIndex = (long) Math.floor((startTime - 1.0) / step) * step;;
TimeCycle timeCycle = TimeCycle.of(step, totalIndex);

// 初始值
cycleResults.add(new CycleResult(timeCycle.calculateStartTime(), 0L));

完整代码

public class TimeWindow {
    /**
     * 分钟数
     */
    private static final String MINUTES = "minutes";
    private static final String COUNT = "count";

    private List<Map<String, Object>> datas = new ArrayList<>();

    @Before
    public void before() {
        // 有序数据
        Map<String, Object> map = new HashMap<String, Object>() {{
            put(MINUTES, "50");
            put(COUNT, 1);
        }};
        Map<String, Object> map2 = new HashMap<String, Object>() {{
            put(MINUTES, "55");
            put(COUNT, 2);
        }};
        Map<String, Object> map3 = new HashMap<String, Object>() {{
            put(MINUTES, "62");
            put(COUNT, 4);
        }};
        Map<String, Object> map4 = new HashMap<String, Object>() {{
            put(MINUTES, "63");
            put(COUNT, 8);
        }};
        datas.add(map);
        datas.add(map2);
        datas.add(map3);
        datas.add(map4);
    }

    @Test
    public void test() {
        List<CycleResult> cycleResultList = collectCoordinate(10);
        System.out.println(JSON.toJSONString(cycleResultList));
        // [{"count":0,"minutesTime":"00:40"},{"count":1,"minutesTime":"00:50"},{"count":2,"minutesTime":"01:00"},{"count":12,"minutesTime":"01:10"}]
    }

    /**
     * 坐标拾取
     * @param step 步长
     */
    public List<CycleResult> collectCoordinate(Integer step) {
        List<CycleResult> cycleResults = new ArrayList<>();

        // 从当前时间所在的时间段开始
        long startTime = Long.parseLong(String.valueOf(datas.get(0).get(MINUTES)));
        long totalIndex = (long) Math.floor((startTime - 1.0) / step) * step;;
        TimeCycle timeCycle = TimeCycle.of(step, totalIndex);

        // 初始值
        cycleResults.add(new CycleResult(timeCycle.calculateStartTime(), 0L));

        for (Map<String, Object> data : datas) {
            Long minutes = data.get(MINUTES) == null ? 0L : Long.parseLong(String.valueOf(data.get(MINUTES)));

            if (timeCycle.getTotalIndex() < minutes) {
                while (timeCycle.getTotalIndex() < minutes) {
                    // 时间段内无值时补0
                    dealData(timeCycle, 0L, cycleResults);
                }
            }

            if (timeCycle.getTotalIndex().equals(minutes)) {
                long count = data.get(COUNT) == null ? 0L : Long.parseLong(String.valueOf(data.get(COUNT)));
                dealData(timeCycle, count, cycleResults);
            }
        }

        // 补全最后一批数据
        if (timeCycle.hasData()) {
            CycleResult cycleResult = new CycleResult();
            cycleResult.setMinutesTime(timeCycle.calculateTime());
            cycleResult.setCount(timeCycle.getCycleCount());
            cycleResults.add(cycleResult);

            timeCycle.reset();
        }
        return cycleResults;
    }

    private void dealData(TimeCycle timeCycle, Long count, List<CycleResult> cycleResults) {
        if (cycleResults == null) {
            cycleResults = new ArrayList<>();
        }

        // 累加
        timeCycle.addCycleCount(count);

        // 若达到了步长值(cycleIndex == step),就记录一个 TimeCycle
        if (timeCycle.needRecord()) {
            CycleResult result = new CycleResult();
            result.setMinutesTime(timeCycle.calculateTime());
            result.setCount(timeCycle.getCycleCount());
            cycleResults.add(result);

            timeCycle.reset();
        } else {
            timeCycle.increaseCycleIndex();
            timeCycle.increaseTotalIndex();
        }
    }
}
@Data
public class TimeCycle {

    private Integer step;
    /**
     * 步长周期里的索引
     */
    private Integer cycleIndex = 0;
    private Long cycleCount = 0L;
    /**
     * 从0开始自增,一直与值做比较,直到最一个数
     */
    private Long totalIndex = 0L;

    private Calendar calendar;

    /**
     * 工厂方法
     * @param step 步长
     */
    public static TimeCycle of(Integer step) {
        TimeCycle timeCycle = new TimeCycle();
        timeCycle.setStep(step);
        return timeCycle;
    }

    public static TimeCycle of(Integer step, Long totalIndex) {
        TimeCycle timeCycle = new TimeCycle();
        timeCycle.setStep(step);
        timeCycle.setTotalIndex(totalIndex);
        return timeCycle;
    }

    public void increaseCycleIndex() {
        this.cycleIndex++;
    }

    public void increaseTotalIndex() {
        this.totalIndex++;
    }

    public void addCycleCount(Long currentCount) {
        if (currentCount == null) {
            return;
        }
        this.cycleCount += currentCount;
    }

    public Calendar getCalendar() {
        if (this.calendar == null) {
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            this.calendar = calendar;
        }
        return this.calendar;
    }

    /**
     * 初始值
     * 时间格式 00:00
     */
    public String calculateStartTime() {
        return calculateTime(this.getRightStep());
    }

    /**
     * Calendar不重置,每次增加一个步长
     */
    public String calculateTime() {
        return calculateTime(this.getStep());
    }

    private String calculateTime(Integer step) {
        Calendar calendar = this.getCalendar();
        calendar.add(Calendar.MINUTE, step);
        return padStart(calendar.get(Calendar.HOUR_OF_DAY)) + ":" + padStart(calendar.get(Calendar.MINUTE));
    }

    private String padStart(int time) {
        // 24小时制是两位数,不够左边补0
        if (time < 10) {
            return "0" + time;
        }
        return String.valueOf(time);
    }

    /**
     * Math.ceil() 向上取整
     * Math.floor() 向下取整
     * Math.round()  四舍五入取整
     */
    private Integer getLeftStep() {
        return (int) Math.floor(totalIndex / (step * 1.0D)) * step;
    }

    private Integer getRightStep() {
        return (int) Math.ceil(totalIndex / (step * 1.0D)) * step;
    }

    public boolean needRecord() {
        return Objects.equals(this.getCycleIndex(), this.getStep());
    }

    public boolean hasData() {
        return !(this.getCycleIndex() == 0 && this.getCycleCount() == 0L);
    }

    public void reset() {
        this.setCycleIndex(0);
        this.setCycleCount(0L);
    }
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class CycleResult {
    private String minutesTime;
    private Long count;
}
上一篇 下一篇

猜你喜欢

热点阅读