使用场景:
给n个员工分配n个案子。条件是按个数比例分配。分配后的案件金额也趋近于个数的比例,并且趋近公平分配。
设计思路
这里比较复杂的地方就是怎么按个数占比分配,案件金额总数也趋近个数占比。并且趋近公平
例如10个按键,案件金额为1,2,3,4,5,6,7,8,9,10
第一种情况偶数分配:
给两个人分案件,一个分配40%一个分配60%,案件个数就是4:6 = 2:3 怎么让金额也趋近2:3
设计思路是先将案件按金额大小排序从头尾获取,第一个人获取四个案件,这四个案件分别从头尾获取,例如当A先获取四个案件是,A拿到的案件分别是1,10,2,9。B获取到的就是3,8,4,7,5,6,金额的比例是 22:33 趋近 2:3的案件占比。
第二种情况奇数数分配:
给两个人分案件,一个分配30%一个分配70%,案件个数就是3:7怎么让金额也趋近3:7=0.42设计思路是还是先将案件按金额大小排序从头尾获取,第一个人获取四个案件,这四个案件分别从头尾获取,例如当 A先获取一个中间的案件然后剩下的按偶数的从头尾取案件,同理第二个人也一样A拿到的案件分别是5,1,10 B获取到的就是6,2,9,3,8,4,7 金额的比例是 16:39=0.41趋近于0.42的案件占比。
当总件数跟百分比的乘机为有小数点的时候,向下取整,比如1.4 取 1。最后一个人直接取剩下所有。
偶数分配图示
奇数分配图示
Java代码:
//*********************************************催收公司分案相关**************************//
@Override
public List<User> updateAutoCaseSplit(CaseHead head,CaseParamsExtend exParams,List<User> users,String tableName) {
if (head == null){
return users;
}
if (users == null || users.size() == 0){
return users;
}
//获取案件
List<CaseHead> heads=caseHeadMapper.getCaseHeadAll(head,exParams,tableName);
if (heads == null || heads.size() == 0){
return users;
}
// 进行分案处理 1.案件金额排序
sortCases(heads);
Integer casecount=heads.size();//案件个数
//将用户排序打乱
Collections.shuffle(users);
List<CaseHead> caselist=new ArrayList<CaseHead>();//剩余案件
caselist=heads;
//循环遍历员工
for (int i = 0; i <users.size() ; i++) {
//计算用户分得几个案子 案件数*百分比
if (i != users.size()-1){
double userCaseCount=casecount*users.get(i).getSplitRate()/100;
Integer count=(int)Math.floor(userCaseCount);
//根据分的案件个数从头尾取值 如果有奇数就奇数在中间取一个变为偶数在头尾取值
if (count%2==0){//偶数
Integer total=count/2; //头尾各取total个
for (int j = 0; j < total; j++) {
int end=caselist.size()-1;
users.get(i).addCaseHead(caselist.get(0));//头
users.get(i).addCaseHead(caselist.get(end));//尾
caselist.remove(end);
caselist.remove(0);
}
}else{//奇数
if (count == 1){//如果只有一个案子那么在中间取一个就退出
int middle=(int)Math.floor(caselist.size()/2);
users.get(i).addCaseHead(caselist.get(middle));//中
caselist.remove(middle);
}else{
//第一个取中间
int middle=(int)Math.floor(caselist.size()/2);
users.get(i).addCaseHead(caselist.get(middle));//中
caselist.remove(middle);
//剩下的跟偶数一致
int total=(count-1)/2;
for (int a = 0; a < total; a++) {
int end=caselist.size()-1;
users.get(i).addCaseHead(caselist.get(0));//头
users.get(i).addCaseHead(caselist.get(end));//尾
caselist.remove(end);
caselist.remove(0);
}
}
}
}else{//最后一个不用计算案件数。剩余案件全是最后一个的这是为了以上几个计算有小数点取整误差
for (CaseHead caseHead : caselist) {
users.get(i).addCaseHead(caseHead);
}
}
}
return users;
}
/**
* 执行分案
* */
@Override
public List<User> updateCaseSplit(List<User> users, String tableName) throws Exception {
for (int i = 0; i <users.size() ; i++) {
}
return null;
}
//案件按照金额排序
private void sortCases(List<CaseHead> caseHeads) {
Collections.sort(caseHeads, new Comparator<CaseHead>() {
@Override
public int compare(CaseHead o1, CaseHead o2) {
return (int) (o2.getMoney() - o1.getMoney()) * 1000;
}
});
}
//*********************************************催收公司分案相关结束************************//
//==================分案相关操作
@Transient
private double splitRate;//分案占比;
@Transient
private double splitTotal;//分案总金额
@Transient
private int splitCount;//分案总件数
@Transient
private List<User> userList;//分案参数
@Transient
private List<CaseHead> caseList;//案件list
public List<CaseHead> getCaseList() {
return caseList;
}
public void setCaseList(List<CaseHead> caseList) {
this.caseList = caseList;
}
public List<User> getUserList() {
return userList;
}
public void setUserList(List<User> userList) {
this.userList = userList;
}
public void addCaseHead(CaseHead caseHead){
if(caseList==null)
caseList=new ArrayList<>();
caseList.add(caseHead);
//总额 件数
splitCount++;
splitTotal+=caseHead.getMoney();
}
将分完的结果通过对象返回给前台页面