场景 要实现一个绳子染色的功能的算法
如图:
一开始是一个红色线段,两端坐标分别为0和100,画上一个蓝色线段后,红色线段被截断,变成红蓝红三个线段,可以重复染色,后来者覆盖,有多种颜色可以染色
线段集合是List ,要求尽可能用Java stream实现画新颜色的draw函数
这里我直接用时间线段进行演示,画图逻辑类似
实现方式如下
声明一个存储时间线段单元的类TeacherAttUnit ,并声明时间的类型枚举AttType
public class TeacherAttUnit {
//考勤类型
enum AttType{
WEI_CHU_QIN("未出勤","weichuqin",1),
CHU_QIN("出勤","chuqin",2),
NIAN_JIA("年假","nianjia",3),
HUN_JIA("婚假","hunjia",4),
SHI_JIA("事假","shijia",5);
public final String name; //此时段的考勤类型
public final String attType; //此时段的考勤类型
public final int sort; //此时段的考勤类型
AttType(String name,String attType,int sort) {
this.name = name;
this.attType = attType;
this.sort = sort;
}
}
public Date startTime; //开始时间
public Date endTime; //结束时间
public AttType attType; //此时段的考勤类型
public List<AttType> attTypeList =new ArrayList<>();//所有出现的考勤类型
public String leaveType;// 假单类型
public Date getStartTime() {
return startTime;
}
public void setStartTime(Date startTime) {
this.startTime = startTime;
}
public Date getEndTime() {
return endTime;
}
public void setEndTime(Date endTime) {
this.endTime = endTime;
}
public AttType getAttType() {
return attType;
}
public void setAttType(AttType attType) {
this.attType = attType;
}
public List<AttType> getAttTypeList() {
return attTypeList;
}
public void setAttTypeList(List<AttType> attTypeList) {
this.attTypeList = attTypeList;
}
public String getLeaveType() {
return leaveType;
}
public void setLeaveType(String leaveType) {
this.leaveType = leaveType;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "\n"+ JSONObject.toJSONString(this);
}
}
再声明一个实现算法的核心计算类,构造函数声明覆盖的时间轴和时间轴的初始化类型
每增加一个新的类型时间段,只需要调用insert方法插入即可
/**
* 考勤计算过程
* @author chenlinhui
*
*/
public class TeacherAttCalculationPress {
//这里防止调用者修改计算过程,声明为私有
private List<TeacherAttUnit> attList; //每个时段的集合
/**
* 初始化计算过程
* @param startTime 时间轴开始时间
* @param endTime 时间轴结束时间
* @param attType 时间轴默认考勤状态
* @param leaveType 时间轴默认请假状态
*/
public TeacherAttCalculationPress(Date startTime,Date endTime,AttType attType, String leaveType){
attList = new LinkedList<TeacherAttUnit>();
TeacherAttUnit attTeacherAttUnit = new TeacherAttUnit();
attTeacherAttUnit.setStartTime(startTime);
attTeacherAttUnit.setEndTime(endTime);
attTeacherAttUnit.setAttType(attType);
attTeacherAttUnit.setLeaveType(leaveType);
attTeacherAttUnit.attTypeList.add(attType);
attList.add(attTeacherAttUnit);
}
//原有数据 2021年9月01日 到2021年9月29日 出勤
//插入数据 2021年9月09日 到 2021年9月19日 类型请假
//结果 2021年9月01日 到2021年9月29日 出勤, 2021年9月29日 到 2021年9月09日 请假, 2021年9月09日 到 2021年9月19日 出勤
/**
* 添加一个假单,第一个添加的假单时间区间是最大需要处理的时间区间
* @param attUnitNew 新加的考勤单元或者假单
*/
public void insert(TeacherAttUnit attUnitNew) {
if (attList == null) {
attList = new LinkedList<TeacherAttUnit>();
}
if (attList.size() == 0) {
attList.add(attUnitNew);
return;
}
//步骤1. 进行线段染色,染色后会出现相邻线段相同颜色情况,下一步需要合并
attList = attList.stream().flatMap((attNode)->{
SimpleDateFormat format = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss" );
List<TeacherAttUnit> flatList = new ArrayList<>();
//以下处理只保留attNode覆盖的时段,所以要求alllist中第一个节点是覆盖全天的
/**
* att ------------
* 情况一 └───────────────────────┘
* 互相无交叉
* */
if (attNode.getStartTime().compareTo(attUnitNew.getEndTime()) >= 0
||attNode.getEndTime().compareTo(attUnitNew.getStartTime()) <= 0) {
flatList.add(attNode);
}
/**
* att ------------
* 情况二 └───────────────────────┘
* 新的包含已有的
* */
else if (attUnitNew.getStartTime().compareTo(attNode.getStartTime()) <= 0
&& attUnitNew.getEndTime().compareTo(attNode.getEndTime()) >= 0) {
attNode.getAttTypeList().add(attUnitNew.attType);
if (attNode.getAttType().sort < attUnitNew.getAttType().sort) {
attNode.setAttType(attUnitNew.attType);
}
flatList.add(attNode);
}
/**
* att ------------------------------
* 情况三 └──────────────┘
* 已有的包含新的
* */
else if (attUnitNew.getStartTime().compareTo(attNode.getStartTime()) > 0
&& attUnitNew.getEndTime().compareTo(attNode.getEndTime()) < 0) {
if (attNode.getAttType().sort < attUnitNew.getAttType().sort) {
//新插入优先级高,时间段被分割成三个时间段
TeacherAttUnit attNew_1 = new TeacherAttUnit();
attNew_1.setStartTime(attNode.getStartTime());
attNew_1.setEndTime(attUnitNew.getStartTime());
attNew_1.setAttType(attNode.getAttType());
attNew_1.getAttTypeList().addAll(attNode.attTypeList);
TeacherAttUnit attNew_2 = new TeacherAttUnit();
attNew_2.setStartTime(attUnitNew.getStartTime());
attNew_2.setEndTime(attUnitNew.getEndTime());
attNew_2.setAttType(attUnitNew.getAttType());
attNew_2.getAttTypeList().addAll(attNode.attTypeList);
attNew_2.getAttTypeList().add(attUnitNew.attType);
TeacherAttUnit attNew_3 = new TeacherAttUnit();
attNew_3.setStartTime(attUnitNew.getEndTime());
attNew_3.setEndTime(attNode.getEndTime());
attNew_3.setAttType(attNode.getAttType());
attNew_3.getAttTypeList().addAll(attNode.attTypeList);
flatList.add(attNew_1);
flatList.add(attNew_2);
flatList.add(attNew_3);
}else {
//保持不变
attNode.getAttTypeList().add(attUnitNew.attType);
flatList.add(attNode);
}
}
/**
* att ------------------------------
* 情况四 └───────────────────────┘
* 交叉一
* */
else if (attUnitNew.startTime.compareTo(attNode.startTime) <= 0
&& attUnitNew.endTime.compareTo(attNode.startTime) > 0
&& attUnitNew.endTime.compareTo(attNode.endTime) < 0) {
if (attNode.getAttType().sort < attUnitNew.getAttType().sort) {
//新插入优先级高,时间段被分割成两个时间段
TeacherAttUnit attNew_2 = new TeacherAttUnit();
attNew_2.setStartTime(attNode.getStartTime());
attNew_2.setEndTime(attUnitNew.getEndTime());
attNew_2.setAttType(attUnitNew.getAttType());
attNew_2.getAttTypeList().addAll(attNode.attTypeList);
attNew_2.getAttTypeList().add(attUnitNew.attType);
TeacherAttUnit attNew_3 = new TeacherAttUnit();
attNew_3.setStartTime(attUnitNew.getEndTime());
attNew_3.setEndTime(attNode.getEndTime());
attNew_3.setAttType(attNode.getAttType());
attNew_3.getAttTypeList().addAll(attNode.attTypeList);
flatList.add(attNew_2);
flatList.add(attNew_3);
}else {
//保持不变
attNode.getAttTypeList().add(attUnitNew.attType);
flatList.add(attNode);
}
}
/**
* att ------------------------------
* 情况五 └───────────────────────┘
* 交叉二
* */
else if (attUnitNew.startTime.compareTo(attNode.startTime) > 0
&& attUnitNew.startTime.compareTo(attNode.endTime) < 0
&& attUnitNew.endTime.compareTo(attNode.endTime) >= 0) {
if (attNode.getAttType().sort < attUnitNew.getAttType().sort) {
//新插入优先级高,时间段被分割成两个时间段
TeacherAttUnit attNew_3 = new TeacherAttUnit();
attNew_3.setStartTime(attNode.getStartTime());
attNew_3.setEndTime(attUnitNew.getStartTime());
attNew_3.setAttType(attNode.getAttType());
attNew_3.getAttTypeList().addAll(attNode.attTypeList);
TeacherAttUnit attNew_2 = new TeacherAttUnit();
attNew_2.setStartTime(attUnitNew.getStartTime());
attNew_2.setEndTime(attNode.getEndTime());
attNew_2.setAttType(attUnitNew.getAttType());
attNew_2.getAttTypeList().addAll(attNode.attTypeList);
attNew_2.getAttTypeList().add(attUnitNew.attType);
flatList.add(attNew_2);
flatList.add(attNew_3);
}else {
//保持不变
attNode.getAttTypeList().add(attUnitNew.attType);
flatList.add(attNode);
}
}
return flatList.stream();
})
//步骤2.排序,为 合并相邻的相同颜色的线段 做准备
.sorted((sortNode1,sortNode2) -> {
//按时间排序
return sortNode1.getStartTime().compareTo(sortNode2.getStartTime());
})
//步骤3:使用规约方法,比较相邻元素,进行合并操作
.reduce(new ArrayList<TeacherAttUnit>(), (result,attNode)->{
//跟最后一个元素相同就合并,不同就添加
if (result.size() >0 && result.get(result.size() - 1).attType.sort == attNode.attType.sort) {
//合并操作,也就是修改最后一个节点结束时间,
result.get(result.size() - 1).setEndTime(attNode.getEndTime());
}else {
result.add(attNode);
}
return result;
},(a,b) -> a);
}
/**
* 统计每个线段,计算并返回考勤结果,这里没有实现,直接用的tostring方法
* @return 计算完的考勤结果 如 出勤几小时,旷工几小时
*/
public String calculationResult() {
return attList.toString();
}
}
声明main函数进行测试
public static void main(String[] args) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date startDate = format.parse("2021-10-11 00:00:00");
Date endTime = format.parse("2021-10-12 00:00:00");
TeacherAttCalculationPress press = new TeacherAttCalculationPress(startDate, endTime, AttType.WEI_CHU_QIN, "");
System.err.println("初始化时间轴》》" + press.attList);
TeacherAttUnit attUnitNew1 = new TeacherAttUnit();
attUnitNew1.setStartTime(format.parse("2021-10-11 09:00:00"));
attUnitNew1.setEndTime(format.parse("2021-10-11 15:00:00"));
attUnitNew1.setAttType(AttType.CHU_QIN);
attUnitNew1.setLeaveType("");
press.insert(attUnitNew1);
System.err.println("增加出勤》》" + press.attList);
TeacherAttUnit attUnitNew = new TeacherAttUnit();
attUnitNew.setStartTime(format.parse("2021-10-11 12:00:00"));
attUnitNew.setEndTime(format.parse("2021-10-11 18:00:00"));
attUnitNew.setAttType(AttType.CHU_QIN);
attUnitNew.setLeaveType("");
press.insert(attUnitNew);
System.err.println("增加交叉出勤》》" + press.attList);
TeacherAttUnit attUnitNew2 = new TeacherAttUnit();
attUnitNew2.setStartTime(format.parse("2021-10-11 16:00:00"));
attUnitNew2.setEndTime(format.parse("2021-10-11 17:00:00"));
attUnitNew2.setAttType(AttType.NIAN_JIA);
attUnitNew2.setLeaveType("");
press.insert(attUnitNew2);
System.err.println("增加年假》》" + press.attList);
}
测试结果
初始化时间轴》》[
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633968000000,"leaveType":"","startTime":1633881600000}]
增加出勤》》[
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633914000000,"startTime":1633881600000},
{"attType":"CHU_QIN","attTypeList":["WEI_CHU_QIN","CHU_QIN"],"endTime":1633935600000,"startTime":1633914000000},
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633968000000,"startTime":1633935600000}]
增加交叉出勤》》[
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633914000000,"startTime":1633881600000},
{"attType":"CHU_QIN","attTypeList":["WEI_CHU_QIN","CHU_QIN","CHU_QIN"],"endTime":1633946400000,"startTime":1633914000000},
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633968000000,"startTime":1633946400000}]
增加年假》》[
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633914000000,"startTime":1633881600000},
{"attType":"CHU_QIN","attTypeList":["WEI_CHU_QIN","CHU_QIN","CHU_QIN"],"endTime":1633939200000,"startTime":1633914000000},
{"attType":"NIAN_JIA","attTypeList":["WEI_CHU_QIN","CHU_QIN","CHU_QIN","NIAN_JIA"],"endTime":1633942800000,"startTime":1633939200000},
{"attType":"CHU_QIN","attTypeList":["WEI_CHU_QIN","CHU_QIN","CHU_QIN"],"endTime":1633946400000,"startTime":1633942800000},
{"attType":"WEI_CHU_QIN","attTypeList":["WEI_CHU_QIN"],"endTime":1633968000000,"startTime":1633946400000}]