使用Java实现给绳子或线段描颜色的算法,基于时间轴的考勤计算算法

场景 要实现一个绳子染色的功能的算法
如图:

img

一开始是一个红色线段,两端坐标分别为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}]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

huihttp

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值