Java实现平均分配算法(附代码)

最近公司有业务需求:要求实现批量分配操作,详情如下:

  1. 选择多个客户
  2. 选择多个员工
  3. 给每个员工分配客户
  4. 要求分配的客户数量尽量平均
  5. 选择的员工数大于选择的客户数时,一个员工分配一个客户,不够的就不分配
  6. 选择的员工数等于客户数时,一个员工对应一个客户
  7. 分配的客户最好是随机的。

为了实现上述需求,需要设计一个随机平均分配算法

  • 一开始我的设计思路比较简单,遍历员工集合和客户集合,依次分配单个客户给每个员工,直到分完为止,但是这种实现效率很低,也达不到随机的效果。
  • 转变思路,先分析、设计数据存储结构,入参为两个List<String>集合,返回数据类型为:
    一、 Map<String, List<String>>,每个员工作为key,value为分配的客户列表;
    二、List<Map<String, List<String>>>,员工作为key,value为分配给他的客户,每个员工-客户列表都对应一个Map<String, List<String>>集合,这样所有的员工-客户列表组合成一个List<Map<String, List<String>>>集合

最终我采用了第二种数据结构,下面是实现代码:

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* @author gxl
* @version 1.0
* @description 平均分配算法
* @date 2019-09-11 08:53
*/
public class AverageDataUtil {

   /**
    * 定义存储待分配数据集合
    */
   private static List<String> list = Lists.newArrayList();

   /**
    * 定义存储分组数据的结构,Map去除泛型,适配多种数据类型格式,使用时需注意
    */
   private static List<Map> los = Lists.newArrayList();

   /**
    * 供外部调用的平均分配方法
    *
    * @param visitorIds 客户列表
    * @param sellerIds  员工列表
    * @return List<Map>
    */
   public static List<Map> averageData(List<String> visitorIds, List<String> sellerIds) {
       initCollections(visitorIds, sellerIds);
       if (visitorIds.size() >= sellerIds.size()) {
           groupByData(los.size());
           return getMaps();
       } else {
           groupByData(list.size());
           return getMaps();
       }
   }

   /**
    * 返回数据,清空静态缓存
    *
    * @return List<Map>
    */
   @NotNull
   private static List<Map> getMaps() {
       List<Map> listMap = Lists.newArrayList();
       listMap.addAll(los);
       //清空静态数据
       los = Lists.newArrayList();
       list = Lists.newArrayList();
       return listMap;
   }

   /**
    * 分配数据
    *
    * @param size       分组大小
    */
   private static void groupByData(int size) {
       List<String> augmented = list;

       List<List<String>> lists = chunk2(augmented, size);

       for (int i = 0; i < size; i++) {
           Map map = los.get(i);
           Iterator iterator = map.keySet().iterator();
           if (iterator.hasNext()) {
               String next = (String) iterator.next();
               map.put(next, lists.get(i));
           }
       }
   }

   /**
    * 初始化集合数据
    *
    * @param visitorIds 待分配数据
    * @param sellerIds  分配目标
    */
   private static void initCollections(List<String> visitorIds, List<String> sellerIds) {
       //每次调用前清空数据
       if (list.size() > 0) {
           list = Lists.newArrayList();
       }
       if (los.size() > 0) {
           los = Lists.newArrayList();
       }
       list.addAll(visitorIds);
       List<Map<String, List<String>>> list1 = new ArrayList<>();
       for (String sellerId : sellerIds) {
           Map<String, List<String>> map = new HashMap<>(16);
           List<String> list = new ArrayList<>();
           map.put(sellerId, list);
           list1.add(map);
       }
       los.addAll(list1);
   }

   /**
    * 分组数据-核心算法,勿动
    *
    * @param list  需分配数据
    * @param group 分组大小
    * @param <T>   分组数据泛型
    * @return 分组结果
    */
   private static <T> List<List<T>> chunk2(List<T> list, int group) {
       if (CollectionUtils.isEmpty(list)) {
           return Lists.newArrayList();
       }
       List<List<T>> result = Lists.newArrayList();
       Map<Integer, Set<T>> temp = Maps.newHashMap();
       for (int i = 0; i < list.size(); i++) {
           if (temp.containsKey(i % group)) {
               Set<T> ts = temp.get(i % group);
               ts.add(list.get(i));
               temp.put(i % group, ts);
           } else {
               Set<T> ts = Sets.newHashSet();
               ts.add(list.get(i));
               temp.put(i % group, ts);
           }
       }
       for (Set<T> ts : temp.values()) {
           result.add(Lists.newArrayList(ts));
       }
       return result;
   }
   
   public static void main(String[] args) {
       List<String> visitorIds = new ArrayList<>();
       visitorIds.add("aa");
       visitorIds.add("bb");
       visitorIds.add("cc");
       visitorIds.add("dd");
       visitorIds.add("ee");
       visitorIds.add("ff");
       visitorIds.add("gg");
       visitorIds.add("hh");
       visitorIds.add("ii");
       visitorIds.add("jj");
       visitorIds.add("kk");
       List<String> sellerIds = new ArrayList<>();
       sellerIds.add("11");
       sellerIds.add("22");
       sellerIds.add("33");
       sellerIds.add("44");
       sellerIds.add("55");
       sellerIds.add("66");
       sellerIds.add("77");
       sellerIds.add("88");
       sellerIds.add("99");
       sellerIds.add("1010");
       sellerIds.add("1111");
       List<Map> maps = averageData(visitorIds, sellerIds);
       System.out.println(maps);
   }

}

这个代码可能还存在部分问题,可以继续优化改进,有什么建议的话,可以在评论区回复,毕竟我也只是个码农,对算法什么的不是很了解 - -

评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值